Merge remote-tracking branch 'upstream/master' into 4.0.0-WIP
Conflicts: spring-integration-core/src/test/java/org/springframework/integration/aggregator/AggregatorTests.java spring-integration-core/src/test/java/org/springframework/integration/aggregator/ConcurrentAggregatorTests.java spring-integration-core/src/test/java/org/springframework/integration/aggregator/CorrelatingMessageHandlerTests.java spring-integration-core/src/test/java/org/springframework/integration/gateway/GatewayInterfaceTests.java spring-integration-redis/src/test/java/org/springframework/integration/redis/channel/SubscribableRedisChannelTests.java spring-integration-redis/src/test/java/org/springframework/integration/redis/config/RedisInboundChannelAdapterParserTests.java spring-integration-redis/src/test/java/org/springframework/integration/redis/store/DelayerHandlerRescheduleIntegrationTests.java spring-integration-redis/src/test/java/org/springframework/integration/redis/store/RedisMessageGroupStoreTests.java spring-integration-redis/src/test/java/org/springframework/integration/redis/store/RedisMessageStoreTests.java Resolved
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -26,3 +26,4 @@ spring-integration-jms/activemq-data/
|
||||
spring-integration-samples/loanshark/application.log*
|
||||
target
|
||||
vf.gf.dmn-*
|
||||
/atlassian-ide-plugin.xml
|
||||
|
||||
@@ -28,7 +28,7 @@ Once you've completed the web form, simply add the following in a comment on you
|
||||
|
||||
## Fork the Repository
|
||||
|
||||
1. Go to [https://github.com/SpringSource/spring-integration](https://github.com/SpringSource/spring-integration)
|
||||
1. Go to [https://github.com/spring-projects/spring-integration](https://github.com/spring-projects/spring-integration)
|
||||
2. Hit the "fork" button and choose your own github account as the target
|
||||
3. For more detail see [http://help.github.com/fork-a-repo/](http://help.github.com/fork-a-repo/)
|
||||
|
||||
@@ -38,7 +38,7 @@ Once you've completed the web form, simply add the following in a comment on you
|
||||
2. `cd spring-integration`
|
||||
3. `git remote show`
|
||||
_you should see only 'origin' - which is the fork you created for your own github account_
|
||||
4. `git remote add upstream git@github.com:SpringSource/spring-integration.git`
|
||||
4. `git remote add upstream git@github.com:spring-projects/spring-integration.git`
|
||||
5. `git remote show`
|
||||
_you should now see 'upstream' in addition to 'origin' where 'upstream' is the SpringSource repository from which releases are built_
|
||||
6. `git fetch --all`
|
||||
@@ -233,4 +233,4 @@ Add a JIRA issue link to your first commit comment of the pull request on the la
|
||||
|
||||
[help documentation]: http://help.github.com/send-pull-requests
|
||||
[JIRA issue tracker]: https://jira.springsource.org/browse/INT
|
||||
[checking out and building]: https://github.com/SpringSource/spring-integration#checking-out-and-building
|
||||
[checking out and building]: https://github.com/spring-projects/spring-integration#checking-out-and-building
|
||||
|
||||
@@ -5,7 +5,7 @@ Spring Integration
|
||||
|
||||
To check out the project and build from source, do the following:
|
||||
|
||||
git clone git://github.com/SpringSource/spring-integration.git
|
||||
git clone git://github.com/spring-projects/spring-integration.git
|
||||
cd spring-integration
|
||||
./gradlew build
|
||||
|
||||
|
||||
14
build.gradle
14
build.gradle
@@ -16,9 +16,9 @@ ext {
|
||||
linkHomepage = 'http://www.springintegration.org/'
|
||||
linkCi = 'https://build.springsource.org/browse/INT'
|
||||
linkIssue = 'https://jira.springsource.org/browse/INT'
|
||||
linkScmUrl = 'https://github.com/SpringSource/spring-integration'
|
||||
linkScmConnection = 'git://github.com/SpringSource/spring-integration.git'
|
||||
linkScmDevConnection = 'git@github.com:SpringSource/spring-integration.git'
|
||||
linkScmUrl = 'https://github.com/spring-projects/spring-integration'
|
||||
linkScmConnection = 'git://github.com/spring-projects/spring-integration.git'
|
||||
linkScmDevConnection = 'git@github.com:spring-projects/spring-integration.git'
|
||||
}
|
||||
|
||||
allprojects {
|
||||
@@ -57,13 +57,16 @@ subprojects { subproject ->
|
||||
log4jVersion = '1.2.12'
|
||||
mockitoVersion = '1.9.5'
|
||||
eaioUUIDVersion = '3.2'
|
||||
ftpServerVersion = '1.0.6'
|
||||
|
||||
|
||||
springVersionDefault = '4.0.0.M3'
|
||||
springVersion = project.hasProperty('springVersion') ? getProperty('springVersion') : springVersionDefault
|
||||
|
||||
springAmqpVersion = '1.2.0.RELEASE'
|
||||
springDataMongoVersion = '1.1.1.RELEASE'
|
||||
springDataRedisVersion = '1.0.5.RELEASE'
|
||||
springDataRedisVersion = '1.1.0.RELEASE'
|
||||
lettuceVersion = '2.3.3'
|
||||
springGemfireVersion = '1.3.1.RELEASE'
|
||||
springSecurityVersion = '3.1.3.RELEASE'
|
||||
springSocialTwitterVersion = '1.0.5.RELEASE'
|
||||
@@ -240,6 +243,7 @@ project('spring-integration-ftp') {
|
||||
compile "org.springframework:spring-context-support:$springVersion"
|
||||
compile("javax.activation:activation:$javaxActivationVersion", optional)
|
||||
testCompile project(":spring-integration-test")
|
||||
testCompile "org.apache.ftpserver:ftpserver-core:$ftpServerVersion"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -436,6 +440,7 @@ project('spring-integration-redis') {
|
||||
exclude group: 'org.springframework', module: 'spring-tx'
|
||||
}
|
||||
testCompile project(":spring-integration-test")
|
||||
testCompile "com.lambdaworks:lettuce:$lettuceVersion"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -538,6 +543,7 @@ project('spring-integration-twitter') {
|
||||
testCompile project(":spring-integration-test")
|
||||
testCompile project(":spring-integration-redis")
|
||||
testCompile project(":spring-integration-redis").sourceSets.test.output
|
||||
testCompile "com.lambdaworks:lettuce:$lettuceVersion"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-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.
|
||||
@@ -27,6 +27,7 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.ManagedMap;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.AbstractSimpleBeanDefinitionParser;
|
||||
import org.springframework.integration.gateway.GatewayProxyFactoryBean;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -34,9 +35,10 @@ import org.springframework.util.xml.DomUtils;
|
||||
|
||||
/**
|
||||
* Parser for the <gateway/> element.
|
||||
*
|
||||
*
|
||||
* @author Mark Fisher
|
||||
* @author Oleg Zhurakousky
|
||||
* @author Gary Russell
|
||||
*/
|
||||
public class GatewayParser extends AbstractSimpleBeanDefinitionParser {
|
||||
|
||||
@@ -51,9 +53,10 @@ public class GatewayParser extends AbstractSimpleBeanDefinitionParser {
|
||||
|
||||
@Override
|
||||
protected String getBeanClassName(Element element) {
|
||||
return IntegrationNamespaceUtils.BASE_PACKAGE + ".gateway.GatewayProxyFactoryBean";
|
||||
return GatewayProxyFactoryBean.class.getName();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected boolean shouldGenerateIdAsFallback() {
|
||||
return true;
|
||||
}
|
||||
@@ -62,6 +65,7 @@ public class GatewayParser extends AbstractSimpleBeanDefinitionParser {
|
||||
protected boolean isEligibleAttribute(String attributeName) {
|
||||
return !ObjectUtils.containsElement(referenceAttributes, attributeName)
|
||||
&& !ObjectUtils.containsElement(innerAttributes, attributeName)
|
||||
&& !("default-payload-expression".equals(attributeName))
|
||||
&& super.isEligibleAttribute(attributeName);
|
||||
}
|
||||
|
||||
@@ -79,7 +83,7 @@ public class GatewayParser extends AbstractSimpleBeanDefinitionParser {
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "request-channel", "defaultRequestChannel");
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "reply-channel", "defaultReplyChannel");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "request-timeout", "defaultRequestTimeout");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "reply-timeout", "defaultReplyTimeout");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "reply-timeout", "defaultReplyTimeout");
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "error-channel");
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "async-executor");
|
||||
}
|
||||
@@ -88,6 +92,18 @@ public class GatewayParser extends AbstractSimpleBeanDefinitionParser {
|
||||
for (String attributeName : referenceAttributes) {
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, attributeName);
|
||||
}
|
||||
|
||||
List<Element> invocationHeaders = DomUtils.getChildElementsByTagName(element, "default-header");
|
||||
if (!CollectionUtils.isEmpty(invocationHeaders)
|
||||
|| StringUtils.hasText(element.getAttribute("default-payload-expression"))) {
|
||||
BeanDefinitionBuilder methodMetadataBuilder = BeanDefinitionBuilder.genericBeanDefinition(
|
||||
"org.springframework.integration.gateway.GatewayMethodMetadata");
|
||||
this.setMethodInvocationHeaders(methodMetadataBuilder, invocationHeaders);
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(methodMetadataBuilder, element,
|
||||
"default-payload-expression", "payloadExpression");
|
||||
builder.addPropertyValue("globalMethodMetadata", methodMetadataBuilder.getBeanDefinition());
|
||||
}
|
||||
|
||||
List<Element> elements = DomUtils.getChildElementsByTagName(element, "method");
|
||||
ManagedMap<String, BeanDefinition> methodMetadataMap = null;
|
||||
if (elements != null && elements.size() > 0) {
|
||||
@@ -102,7 +118,7 @@ public class GatewayParser extends AbstractSimpleBeanDefinitionParser {
|
||||
methodMetadataBuilder.addPropertyValue("requestTimeout", methodElement.getAttribute("request-timeout"));
|
||||
methodMetadataBuilder.addPropertyValue("replyTimeout", methodElement.getAttribute("reply-timeout"));
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(methodMetadataBuilder, methodElement, "payload-expression");
|
||||
List<Element> invocationHeaders = DomUtils.getChildElementsByTagName(methodElement, "header");
|
||||
invocationHeaders = DomUtils.getChildElementsByTagName(methodElement, "header");
|
||||
if (!CollectionUtils.isEmpty(invocationHeaders)) {
|
||||
this.setMethodInvocationHeaders(methodMetadataBuilder, invocationHeaders);
|
||||
}
|
||||
|
||||
@@ -68,6 +68,7 @@ import org.springframework.util.StringUtils;
|
||||
* @author Mark Fisher
|
||||
* @author Iwein Fuld
|
||||
* @author Oleg Zhurakousky
|
||||
* @author Gary Russell
|
||||
* @since 2.0
|
||||
*/
|
||||
class GatewayMethodInboundMessageMapper implements InboundMessageMapper<Object[]>, BeanFactoryAware {
|
||||
@@ -80,6 +81,8 @@ class GatewayMethodInboundMessageMapper implements InboundMessageMapper<Object[]
|
||||
|
||||
private final Map<String, Expression> headerExpressions;
|
||||
|
||||
private final Map<String, Expression> globalHeaderExpressions;
|
||||
|
||||
private final List<MethodParameter> parameterList;
|
||||
|
||||
private volatile Expression payloadExpression;
|
||||
@@ -96,9 +99,15 @@ class GatewayMethodInboundMessageMapper implements InboundMessageMapper<Object[]
|
||||
}
|
||||
|
||||
public GatewayMethodInboundMessageMapper(Method method, Map<String, Expression> headerExpressions) {
|
||||
this(method, headerExpressions, null);
|
||||
}
|
||||
|
||||
public GatewayMethodInboundMessageMapper(Method method, Map<String, Expression> headerExpressions,
|
||||
Map<String, Expression> globalHeaderExpressions) {
|
||||
Assert.notNull(method, "method must not be null");
|
||||
this.method = method;
|
||||
this.headerExpressions = headerExpressions;
|
||||
this.globalHeaderExpressions = globalHeaderExpressions;
|
||||
this.parameterList = getMethodParameterList(method);
|
||||
this.payloadExpression = parsePayloadExpression(method);
|
||||
}
|
||||
@@ -194,23 +203,38 @@ class GatewayMethodInboundMessageMapper implements InboundMessageMapper<Object[]
|
||||
? MessageBuilder.fromMessage((Message<?>) messageOrPayload)
|
||||
: MessageBuilder.withPayload(messageOrPayload);
|
||||
builder.copyHeadersIfAbsent(headers);
|
||||
// Explicit headers in XML override any @Header annotations...
|
||||
if (!CollectionUtils.isEmpty(this.headerExpressions)) {
|
||||
Map<String, Object> evaluatedHeaders = new HashMap<String, Object>();
|
||||
for (Map.Entry<String, Expression> entry : this.headerExpressions.entrySet()) {
|
||||
Object value = entry.getValue().getValue(methodInvocationEvaluationContext);
|
||||
if (value != null) {
|
||||
evaluatedHeaders.put(entry.getKey(), value);
|
||||
}
|
||||
}
|
||||
Map<String, Object> evaluatedHeaders = evaluateHeaders(methodInvocationEvaluationContext, this.headerExpressions);
|
||||
builder.copyHeaders(evaluatedHeaders);
|
||||
}
|
||||
// ...whereas global (default) headers do not...
|
||||
if (!CollectionUtils.isEmpty(this.globalHeaderExpressions)) {
|
||||
Map<String, Object> evaluatedHeaders = evaluateHeaders(methodInvocationEvaluationContext, this.globalHeaderExpressions);
|
||||
builder.copyHeadersIfAbsent(evaluatedHeaders);
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private Map<String, Object> evaluateHeaders(EvaluationContext methodInvocationEvaluationContext, Map<String, Expression> headerExpressions) {
|
||||
Map<String, Object> evaluatedHeaders = new HashMap<String, Object>();
|
||||
for (Map.Entry<String, Expression> entry : headerExpressions.entrySet()) {
|
||||
Object value = entry.getValue().getValue(methodInvocationEvaluationContext);
|
||||
if (value != null) {
|
||||
evaluatedHeaders.put(entry.getKey(), value);
|
||||
}
|
||||
}
|
||||
return evaluatedHeaders;
|
||||
}
|
||||
|
||||
private StandardEvaluationContext createMethodInvocationEvaluationContext(Object[] arguments) {
|
||||
StandardEvaluationContext context = ExpressionUtils.createStandardEvaluationContext(this.beanFactory);
|
||||
context.setVariable("args", arguments);
|
||||
|
||||
// TODO deprecated in 3.0/4.0 - retained for backwards compatibility
|
||||
context.setVariable("method", this.method.getName());
|
||||
|
||||
context.setVariable("gatewayMethod", this.method);
|
||||
return context;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-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.
|
||||
@@ -28,6 +28,7 @@ import java.util.concurrent.Future;
|
||||
|
||||
import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
|
||||
import org.springframework.aop.framework.ProxyFactory;
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.beans.SimpleTypeConverter;
|
||||
@@ -100,8 +101,9 @@ public class GatewayProxyFactoryBean extends AbstractEndpoint implements Trackab
|
||||
|
||||
private final Object initializationMonitor = new Object();
|
||||
|
||||
private Map<String, GatewayMethodMetadata> methodMetadataMap;
|
||||
private volatile Map<String, GatewayMethodMetadata> methodMetadataMap;
|
||||
|
||||
private volatile GatewayMethodMetadata globalMethodMetadata;
|
||||
|
||||
/**
|
||||
* Create a Factory whose service interface type can be configured by setter injection.
|
||||
@@ -204,6 +206,10 @@ public class GatewayProxyFactoryBean extends AbstractEndpoint implements Trackab
|
||||
this.methodMetadataMap = methodMetadataMap;
|
||||
}
|
||||
|
||||
public void setGlobalMethodMetadata(GatewayMethodMetadata globalMethodMetadata) {
|
||||
this.globalMethodMetadata = globalMethodMetadata;
|
||||
}
|
||||
|
||||
public void setBeanClassLoader(ClassLoader beanClassLoader) {
|
||||
this.beanClassLoader = beanClassLoader;
|
||||
}
|
||||
@@ -339,7 +345,8 @@ public class GatewayProxyFactoryBean extends AbstractEndpoint implements Trackab
|
||||
MessageChannel replyChannel = this.defaultReplyChannel;
|
||||
Long requestTimeout = this.defaultRequestTimeout;
|
||||
Long replyTimeout = this.defaultReplyTimeout;
|
||||
String payloadExpression = null;
|
||||
String payloadExpression = this.globalMethodMetadata != null ? this.globalMethodMetadata.getPayloadExpression()
|
||||
: null;
|
||||
Map<String, Expression> headerExpressions = null;
|
||||
if (gatewayAnnotation != null) {
|
||||
String requestChannelName = gatewayAnnotation.requestChannel();
|
||||
@@ -387,7 +394,8 @@ public class GatewayProxyFactoryBean extends AbstractEndpoint implements Trackab
|
||||
}
|
||||
}
|
||||
}
|
||||
GatewayMethodInboundMessageMapper messageMapper = new GatewayMethodInboundMessageMapper(method, headerExpressions);
|
||||
GatewayMethodInboundMessageMapper messageMapper = new GatewayMethodInboundMessageMapper(method, headerExpressions,
|
||||
this.globalMethodMetadata != null ? this.globalMethodMetadata.getHeaderExpressions() : null);
|
||||
if (StringUtils.hasText(payloadExpression)) {
|
||||
messageMapper.setPayloadExpression(payloadExpression);
|
||||
}
|
||||
|
||||
@@ -515,7 +515,17 @@
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:sequence minOccurs="0" maxOccurs="1">
|
||||
<xsd:element name="default-header" minOccurs="0" maxOccurs="unbounded" type="headerSubElementType">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
Provides a mechanism to enrich the message with custom message headers. These default headers are created for
|
||||
all methods on the service-interface (unless overridden by a specific method element).
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
<xsd:element name="method" minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
@@ -530,7 +540,7 @@
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
Provides mechanism to enrich content of the message with custom message headers. When this method is going to be invoked
|
||||
Provides a mechanism to enrich the message with custom message headers. When this method is invoked,
|
||||
the generated message will be enriched with these headers.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
@@ -621,6 +631,17 @@
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="default-payload-expression" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
An expression that will be used to generate the payload for all methods in the service interface
|
||||
unless explicitly overriden by a method declaration. Variables include #args, #methodName, #methodString
|
||||
and #methodObject; a bean resolver is also available, enabling expressions like "@someBean(#args)".
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="default-request-channel" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-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
|
||||
@@ -19,21 +19,18 @@ import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.integration.MessageHandlingException;
|
||||
import org.springframework.messaging.MessageHeaders;
|
||||
import org.springframework.integration.channel.QueueChannel;
|
||||
import org.springframework.integration.store.MessageGroup;
|
||||
import org.springframework.integration.store.SimpleMessageStore;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.messaging.MessageHeaders;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
@@ -44,7 +41,7 @@ public class AggregatorTests {
|
||||
|
||||
private AggregatingMessageHandler aggregator;
|
||||
|
||||
private SimpleMessageStore store = new SimpleMessageStore(50);
|
||||
private final SimpleMessageStore store = new SimpleMessageStore(50);
|
||||
|
||||
|
||||
@Before
|
||||
@@ -59,12 +56,12 @@ public class AggregatorTests {
|
||||
Message<?> message1 = createMessage(3, "ABC", 3, 1, replyChannel, null);
|
||||
Message<?> message2 = createMessage(5, "ABC", 3, 2, replyChannel, null);
|
||||
Message<?> message3 = createMessage(7, "ABC", 3, 3, replyChannel, null);
|
||||
CountDownLatch latch = new CountDownLatch(3);
|
||||
|
||||
this.aggregator.handleMessage(message1);
|
||||
this.aggregator.handleMessage(message2);
|
||||
this.aggregator.handleMessage(message3);
|
||||
latch.await(1000, TimeUnit.MILLISECONDS);
|
||||
Message<?> reply = replyChannel.receive(2000);
|
||||
|
||||
Message<?> reply = replyChannel.receive(10000);
|
||||
assertNotNull(reply);
|
||||
assertEquals(reply.getPayload(), 105);
|
||||
}
|
||||
@@ -77,7 +74,7 @@ public class AggregatorTests {
|
||||
Message<?> message = createMessage(3, "ABC", 2, 1, replyChannel, null);
|
||||
this.aggregator.handleMessage(message);
|
||||
this.store.expireMessageGroups(-10000);
|
||||
Message<?> reply = replyChannel.receive(100);
|
||||
Message<?> reply = replyChannel.receive(1000);
|
||||
assertNull("No message should have been sent normally", reply);
|
||||
Message<?> discardedMessage = discardChannel.receive(1000);
|
||||
assertNotNull("A message should have been discarded", discardedMessage);
|
||||
@@ -93,7 +90,7 @@ public class AggregatorTests {
|
||||
this.aggregator.handleMessage(message1);
|
||||
this.aggregator.handleMessage(message2);
|
||||
this.store.expireMessageGroups(-10000);
|
||||
Message<?> reply = replyChannel.receive(0);
|
||||
Message<?> reply = replyChannel.receive(1000);
|
||||
assertNotNull("A reply message should have been received", reply);
|
||||
assertEquals(15, reply.getPayload());
|
||||
}
|
||||
@@ -115,11 +112,11 @@ public class AggregatorTests {
|
||||
aggregator.handleMessage(message4);
|
||||
aggregator.handleMessage(message2);
|
||||
@SuppressWarnings("unchecked")
|
||||
Message<Integer> reply1 = (Message<Integer>) replyChannel1.receive(500);
|
||||
Message<Integer> reply1 = (Message<Integer>) replyChannel1.receive(1000);
|
||||
assertNotNull(reply1);
|
||||
assertThat(reply1.getPayload(), is(105));
|
||||
@SuppressWarnings("unchecked")
|
||||
Message<Integer> reply2 = (Message<Integer>) replyChannel2.receive(500);
|
||||
Message<Integer> reply2 = (Message<Integer>) replyChannel2.receive(1000);
|
||||
assertNotNull(reply2);
|
||||
assertThat(reply2.getPayload(), is(2431));
|
||||
}
|
||||
@@ -133,14 +130,14 @@ public class AggregatorTests {
|
||||
|
||||
this.aggregator.setDiscardChannel(discardChannel);
|
||||
this.aggregator.handleMessage(createMessage(1, 1, 1, 1, replyChannel, null));
|
||||
assertEquals(1, replyChannel.receive(100).getPayload());
|
||||
assertEquals(1, replyChannel.receive(1000).getPayload());
|
||||
this.aggregator.handleMessage(createMessage(3, 2, 1, 1, replyChannel, null));
|
||||
assertEquals(3, replyChannel.receive(100).getPayload());
|
||||
assertEquals(3, replyChannel.receive(1000).getPayload());
|
||||
this.aggregator.handleMessage(createMessage(4, 3, 1, 1, replyChannel, null));
|
||||
assertEquals(4, replyChannel.receive(100).getPayload());
|
||||
assertEquals(4, replyChannel.receive(1000).getPayload());
|
||||
// next message with same correllation ID is discarded
|
||||
this.aggregator.handleMessage(createMessage(2, 1, 1, 1, replyChannel, null));
|
||||
assertEquals(2, discardChannel.receive(100).getPayload());
|
||||
assertEquals(2, discardChannel.receive(1000).getPayload());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -152,15 +149,15 @@ public class AggregatorTests {
|
||||
|
||||
this.aggregator.setDiscardChannel(discardChannel);
|
||||
this.aggregator.handleMessage(createMessage(1, 1, 1, 1, replyChannel, null));
|
||||
assertEquals(1, replyChannel.receive(100).getPayload());
|
||||
assertEquals(1, replyChannel.receive(1000).getPayload());
|
||||
this.aggregator.handleMessage(createMessage(2, 2, 1, 1, replyChannel, null));
|
||||
assertEquals(2, replyChannel.receive(100).getPayload());
|
||||
assertEquals(2, replyChannel.receive(1000).getPayload());
|
||||
this.aggregator.handleMessage(createMessage(3, 3, 1, 1, replyChannel, null));
|
||||
assertEquals(3, replyChannel.receive(100).getPayload());
|
||||
assertEquals(3, replyChannel.receive(1000).getPayload());
|
||||
this.aggregator.handleMessage(createMessage(4, 4, 1, 1, replyChannel, null));
|
||||
assertEquals(4, replyChannel.receive(100).getPayload());
|
||||
assertEquals(4, replyChannel.receive(1000).getPayload());
|
||||
this.aggregator.handleMessage(createMessage(5, 1, 1, 1, replyChannel, null));
|
||||
assertEquals(5, replyChannel.receive(100).getPayload());
|
||||
assertEquals(5, replyChannel.receive(1000).getPayload());
|
||||
assertNull(discardChannel.receive(0));
|
||||
}
|
||||
|
||||
@@ -177,15 +174,13 @@ public class AggregatorTests {
|
||||
Message<?> message2 = createMessage(5, "ABC", 3, 2, replyChannel, null);
|
||||
Message<?> message3 = createMessage(7, "ABC", 3, 3, replyChannel, null);
|
||||
Message<?> message4 = createMessage(7, "ABC", 3, 3, replyChannel, null);
|
||||
CountDownLatch latch = new CountDownLatch(4);
|
||||
|
||||
this.aggregator.handleMessage(message1);
|
||||
this.aggregator.handleMessage(message2);
|
||||
this.aggregator.handleMessage(message3);
|
||||
this.aggregator.handleMessage(message4);
|
||||
latch.await(1000, TimeUnit.MILLISECONDS);
|
||||
// small wait to make sure the fourth message is received
|
||||
Thread.sleep(10);
|
||||
Message<?> reply = replyChannel.receive(0);
|
||||
|
||||
Message<?> reply = replyChannel.receive(10000);
|
||||
assertNotNull("A message should be aggregated", reply);
|
||||
assertThat(((Integer) reply.getPayload()), is(105));
|
||||
}
|
||||
@@ -197,18 +192,19 @@ public class AggregatorTests {
|
||||
Message<?> message2 = createMessage(5, "ABC", 3, 2, replyChannel, null);
|
||||
Message<?> message3 = createMessage(7, "ABC", 3, 3, replyChannel, null);
|
||||
Message<?> message4 = createMessage(7, "ABC", 3, 3, replyChannel, null);
|
||||
CountDownLatch latch = new CountDownLatch(4);
|
||||
|
||||
this.aggregator.handleMessage(message1);
|
||||
this.aggregator.handleMessage(message3);
|
||||
// duplicated sequence number, either message3 or message4 should be rejected
|
||||
this.aggregator.handleMessage(message4);
|
||||
this.aggregator.handleMessage(message2);
|
||||
latch.await(1000, TimeUnit.MILLISECONDS);
|
||||
Message<?> reply = replyChannel.receive(0);
|
||||
|
||||
Message<?> reply = replyChannel.receive(10000);
|
||||
assertNotNull("A message should be aggregated", reply);
|
||||
assertThat(((Integer) reply.getPayload()), is(105));
|
||||
}
|
||||
|
||||
|
||||
private static Message<?> createMessage(Object payload, Object correlationId, int sequenceSize, int sequenceNumber,
|
||||
MessageChannel replyChannel, String predefinedId) {
|
||||
MessageBuilder<Object> builder = MessageBuilder.withPayload(payload).setCorrelationId(correlationId)
|
||||
@@ -231,10 +227,4 @@ public class AggregatorTests {
|
||||
}
|
||||
|
||||
|
||||
private class NullReturningMessageProcessor implements MessageGroupProcessor {
|
||||
public Object processMessageGroup(MessageGroup group) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-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.
|
||||
@@ -16,31 +16,32 @@
|
||||
|
||||
package org.springframework.integration.aggregator;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.core.task.SimpleAsyncTaskExecutor;
|
||||
import org.springframework.core.task.TaskExecutor;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.integration.MessageHandlingException;
|
||||
import org.springframework.messaging.MessageHeaders;
|
||||
import org.springframework.integration.channel.QueueChannel;
|
||||
import org.springframework.messaging.MessageHandler;
|
||||
import org.springframework.integration.store.MessageGroup;
|
||||
import org.springframework.integration.store.MessageGroupStore;
|
||||
import org.springframework.integration.store.SimpleMessageStore;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.messaging.MessageHandler;
|
||||
import org.springframework.messaging.MessageHeaders;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
@@ -53,7 +54,7 @@ public class ConcurrentAggregatorTests {
|
||||
|
||||
private AggregatingMessageHandler aggregator;
|
||||
|
||||
private MessageGroupStore store = new SimpleMessageStore();
|
||||
private final MessageGroupStore store = new SimpleMessageStore();
|
||||
|
||||
|
||||
@Before
|
||||
@@ -76,7 +77,9 @@ public class ConcurrentAggregatorTests {
|
||||
message2, latch));
|
||||
this.taskExecutor.execute(new AggregatorTestTask(this.aggregator,
|
||||
message3, latch));
|
||||
latch.await(10000, TimeUnit.MILLISECONDS);
|
||||
|
||||
assertTrue(latch.await(10, TimeUnit.SECONDS));
|
||||
|
||||
assertThat(latch.getCount(), is(0l));
|
||||
Message<?> reply = replyChannel.receive(2000);
|
||||
assertNotNull(reply);
|
||||
@@ -101,7 +104,7 @@ public class ConcurrentAggregatorTests {
|
||||
new AggregatorTestTask(this.aggregator, message1, latch).run();
|
||||
new AggregatorTestTask(this.aggregator, message2, latch).run();
|
||||
new AggregatorTestTask(this.aggregator, message3, latch).run();
|
||||
Message<?> reply = replyChannel.receive(500);
|
||||
Message<?> reply = replyChannel.receive(1000);
|
||||
assertNotNull(reply);
|
||||
assertEquals("123456789", reply.getPayload());
|
||||
}
|
||||
@@ -117,13 +120,15 @@ public class ConcurrentAggregatorTests {
|
||||
AggregatorTestTask task = new AggregatorTestTask(this.aggregator,
|
||||
message, latch);
|
||||
this.taskExecutor.execute(task);
|
||||
latch.await(200, TimeUnit.MILLISECONDS);
|
||||
|
||||
assertTrue(latch.await(10, TimeUnit.SECONDS));
|
||||
|
||||
assertEquals("Task should have completed within timeout", 0, latch
|
||||
.getCount());
|
||||
Message<?> reply = replyChannel.receive(100);
|
||||
Message<?> reply = replyChannel.receive(1000);
|
||||
assertNull("No message should have been sent normally", reply);
|
||||
this.store.expireMessageGroups(-10000);
|
||||
Message<?> discardedMessage = discardChannel.receive(100);
|
||||
Message<?> discardedMessage = discardChannel.receive(1000);
|
||||
assertNotNull("A message should have been discarded", discardedMessage);
|
||||
assertEquals(message, discardedMessage);
|
||||
}
|
||||
@@ -142,11 +147,13 @@ public class ConcurrentAggregatorTests {
|
||||
message2, latch);
|
||||
this.taskExecutor.execute(task1);
|
||||
this.taskExecutor.execute(task2);
|
||||
latch.await(300, TimeUnit.MILLISECONDS);
|
||||
|
||||
assertTrue(latch.await(10, TimeUnit.SECONDS));
|
||||
|
||||
assertEquals("handlers should have been invoked within time limit", 0,
|
||||
latch.getCount());
|
||||
this.store.expireMessageGroups(-10000);
|
||||
Message<?> reply = replyChannel.receive(100);
|
||||
Message<?> reply = replyChannel.receive(1000);
|
||||
assertNotNull("A reply message should have been received", reply);
|
||||
assertEquals(15, reply.getPayload());
|
||||
assertNull(task1.getException());
|
||||
@@ -179,13 +186,15 @@ public class ConcurrentAggregatorTests {
|
||||
message3, latch));
|
||||
this.taskExecutor.execute(new AggregatorTestTask(this.aggregator,
|
||||
message4, latch));
|
||||
latch.await(1000, TimeUnit.MILLISECONDS);
|
||||
|
||||
assertTrue(latch.await(10, TimeUnit.SECONDS));
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Message<Integer> reply1 = (Message<Integer>) replyChannel1.receive(500);
|
||||
Message<Integer> reply1 = (Message<Integer>) replyChannel1.receive(1000);
|
||||
assertNotNull(reply1);
|
||||
assertThat(reply1.getPayload(), is(105));
|
||||
@SuppressWarnings("unchecked")
|
||||
Message<Integer> reply2 = (Message<Integer>) replyChannel2.receive(500);
|
||||
Message<Integer> reply2 = (Message<Integer>) replyChannel2.receive(1000);
|
||||
assertNotNull(reply2);
|
||||
assertThat(reply2.getPayload(), is(2431));
|
||||
}
|
||||
@@ -201,17 +210,17 @@ public class ConcurrentAggregatorTests {
|
||||
this.aggregator.setDiscardChannel(discardChannel);
|
||||
this.aggregator.handleMessage(createMessage(1, 1, 1, 1, replyChannel,
|
||||
null));
|
||||
assertEquals(1, replyChannel.receive(100).getPayload());
|
||||
assertEquals(1, replyChannel.receive(1000).getPayload());
|
||||
this.aggregator.handleMessage(createMessage(3, 2, 1, 1, replyChannel,
|
||||
null));
|
||||
assertEquals(3, replyChannel.receive(100).getPayload());
|
||||
assertEquals(3, replyChannel.receive(1000).getPayload());
|
||||
this.aggregator.handleMessage(createMessage(4, 3, 1, 1, replyChannel,
|
||||
null));
|
||||
assertEquals(4, replyChannel.receive(100).getPayload());
|
||||
assertEquals(4, replyChannel.receive(1000).getPayload());
|
||||
// next message with same correlation ID is discarded
|
||||
this.aggregator.handleMessage(createMessage(2, 1, 1, 1, replyChannel,
|
||||
null));
|
||||
assertEquals(2, discardChannel.receive(100).getPayload());
|
||||
assertEquals(2, discardChannel.receive(1000).getPayload());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -225,19 +234,19 @@ public class ConcurrentAggregatorTests {
|
||||
this.aggregator.setDiscardChannel(discardChannel);
|
||||
this.aggregator.handleMessage(createMessage(1, 1, 1, 1, replyChannel,
|
||||
null));
|
||||
assertEquals(1, replyChannel.receive(100).getPayload());
|
||||
assertEquals(1, replyChannel.receive(1000).getPayload());
|
||||
this.aggregator.handleMessage(createMessage(2, 2, 1, 1, replyChannel,
|
||||
null));
|
||||
assertEquals(2, replyChannel.receive(100).getPayload());
|
||||
assertEquals(2, replyChannel.receive(1000).getPayload());
|
||||
this.aggregator.handleMessage(createMessage(3, 3, 1, 1, replyChannel,
|
||||
null));
|
||||
assertEquals(3, replyChannel.receive(100).getPayload());
|
||||
assertEquals(3, replyChannel.receive(1000).getPayload());
|
||||
this.aggregator.handleMessage(createMessage(4, 4, 1, 1, replyChannel,
|
||||
null));
|
||||
assertEquals(4, replyChannel.receive(100).getPayload());
|
||||
assertEquals(4, replyChannel.receive(1000).getPayload());
|
||||
this.aggregator.handleMessage(createMessage(5, 1, 1, 1, replyChannel,
|
||||
null));
|
||||
assertEquals(5, replyChannel.receive(100).getPayload());
|
||||
assertEquals(5, replyChannel.receive(1000).getPayload());
|
||||
assertNull(discardChannel.receive(0));
|
||||
}
|
||||
|
||||
@@ -266,12 +275,15 @@ public class ConcurrentAggregatorTests {
|
||||
message3, latch));
|
||||
this.taskExecutor.execute(new AggregatorTestTask(this.aggregator,
|
||||
message4, latch));
|
||||
latch.await(1000, TimeUnit.MILLISECONDS);
|
||||
Message<?> reply = replyChannel.receive(100);
|
||||
|
||||
assertTrue(latch.await(10, TimeUnit.SECONDS));
|
||||
|
||||
Message<?> reply = replyChannel.receive(1000);
|
||||
assertNotNull("A message should be aggregated", reply);
|
||||
assertThat(((Integer) reply.getPayload()), is(105));
|
||||
}
|
||||
|
||||
|
||||
private static Message<?> createMessage(Object payload,
|
||||
Object correlationId, int sequenceSize, int sequenceNumber,
|
||||
MessageChannel replyChannel, String predefinedId) {
|
||||
@@ -288,13 +300,13 @@ public class ConcurrentAggregatorTests {
|
||||
|
||||
private static class AggregatorTestTask implements Runnable {
|
||||
|
||||
private MessageHandler aggregator;
|
||||
private final MessageHandler aggregator;
|
||||
|
||||
private Message<?> message;
|
||||
private final Message<?> message;
|
||||
|
||||
private Exception exception;
|
||||
|
||||
private CountDownLatch latch;
|
||||
private final CountDownLatch latch;
|
||||
|
||||
AggregatorTestTask(MessageHandler aggregator, Message<?> message,
|
||||
CountDownLatch latch) {
|
||||
|
||||
@@ -17,18 +17,20 @@
|
||||
package org.springframework.integration.aggregator;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyLong;
|
||||
import static org.mockito.Matchers.isA;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.mockito.Mockito.any;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -36,6 +38,7 @@ import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.internal.stubbing.answers.ThrowsException;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
import org.springframework.integration.MessageHandlingException;
|
||||
import org.springframework.integration.store.MessageGroup;
|
||||
import org.springframework.integration.store.MessageGroupStore;
|
||||
@@ -57,7 +60,7 @@ public class CorrelatingMessageHandlerTests {
|
||||
@Mock
|
||||
private CorrelationStrategy correlationStrategy;
|
||||
|
||||
private ReleaseStrategy ReleaseStrategy = new SequenceSizeReleaseStrategy();
|
||||
private final ReleaseStrategy ReleaseStrategy = new SequenceSizeReleaseStrategy();
|
||||
|
||||
@Mock
|
||||
private MessageGroupProcessor processor;
|
||||
@@ -65,7 +68,7 @@ public class CorrelatingMessageHandlerTests {
|
||||
@Mock
|
||||
private MessageChannel outputChannel;
|
||||
|
||||
private MessageGroupStore store = new SimpleMessageStore();
|
||||
private final MessageGroupStore store = new SimpleMessageStore();
|
||||
|
||||
|
||||
@Before
|
||||
@@ -152,10 +155,9 @@ public class CorrelatingMessageHandlerTests {
|
||||
}
|
||||
});
|
||||
|
||||
Thread.sleep(20);
|
||||
assertEquals(0, store.expireMessageGroups(10000));
|
||||
assertTrue(bothMessagesHandled.await(10, TimeUnit.SECONDS));
|
||||
|
||||
bothMessagesHandled.await();
|
||||
assertEquals(0, store.expireMessageGroups(10000));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-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
|
||||
@@ -12,6 +12,9 @@
|
||||
*/
|
||||
package org.springframework.integration.aggregator.scenarios;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@@ -24,9 +27,6 @@ import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.integration.channel.QueueChannel;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Oleg Zhurakousky
|
||||
*
|
||||
@@ -79,11 +79,11 @@ public class AggregatorWithCustomReleaseStrategyTests {
|
||||
|
||||
assertTrue("Sends failed to complete", latch.await(10, TimeUnit.SECONDS));
|
||||
|
||||
Message<?> message = resultChannel.receive(10);
|
||||
Message<?> message = resultChannel.receive(1000);
|
||||
int counter = 0;
|
||||
while(message != null){
|
||||
counter++;
|
||||
message = resultChannel.receive(10);
|
||||
message = resultChannel.receive(1000);
|
||||
}
|
||||
assertEquals(600, counter);
|
||||
}
|
||||
@@ -119,10 +119,10 @@ public class AggregatorWithCustomReleaseStrategyTests {
|
||||
|
||||
assertTrue("Sends failed to complete", latch.await(10, TimeUnit.SECONDS));
|
||||
|
||||
Message<?> message = resultChannel.receive(10);
|
||||
Message<?> message = resultChannel.receive(1000);
|
||||
int counter = 0;
|
||||
while(message != null && ++counter < 7200){
|
||||
message = resultChannel.receive(10);
|
||||
message = resultChannel.receive(1000);
|
||||
}
|
||||
assertEquals(7200, counter);
|
||||
}
|
||||
|
||||
@@ -5,10 +5,17 @@
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd">
|
||||
|
||||
<int:gateway id="sampleGateway"
|
||||
service-interface="org.springframework.integration.gateway.GatewayInterfaceTests.Bar"
|
||||
default-request-channel="requestChannelBaz"/>
|
||||
|
||||
<int:gateway id="sampleGateway"
|
||||
service-interface="org.springframework.integration.gateway.GatewayInterfaceTests.Bar"
|
||||
default-request-channel="requestChannelBaz">
|
||||
<int:default-header name="name" expression="#gatewayMethod.name"/>
|
||||
<int:default-header name="string" expression="#gatewayMethod.toString()"/>
|
||||
<int:default-header name="object" expression="#gatewayMethod"/>
|
||||
<int:method name="baz">
|
||||
<int:header name="name" value="overrideGlobal"/>
|
||||
</int:method>
|
||||
</int:gateway>
|
||||
|
||||
<int:channel id="requestChannelFoo"/>
|
||||
<int:channel id="requestChannelBar"/>
|
||||
<int:channel id="requestChannelBaz"/>
|
||||
|
||||
@@ -16,43 +16,90 @@
|
||||
|
||||
package org.springframework.integration.gateway;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.integration.annotation.Gateway;
|
||||
import org.springframework.integration.annotation.Header;
|
||||
import org.springframework.integration.channel.DirectChannel;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageHandler;
|
||||
import org.springframework.messaging.MessagingException;
|
||||
|
||||
/**
|
||||
* @author Oleg Zhurakousky
|
||||
* @author Gunnar Hillert
|
||||
* @author Gary Russell
|
||||
*/
|
||||
public class GatewayInterfaceTests {
|
||||
|
||||
@Test
|
||||
public void testWithServiceSuperclassAnnotatedMethod(){
|
||||
public void testWithServiceSuperclassAnnotatedMethod() throws Exception {
|
||||
ApplicationContext ac = new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", this.getClass());
|
||||
DirectChannel channel = ac.getBean("requestChannelFoo", DirectChannel.class);
|
||||
MessageHandler handler = mock(MessageHandler.class);
|
||||
final Method fooMethod = Foo.class.getMethod("foo", String.class);
|
||||
final AtomicBoolean called = new AtomicBoolean();
|
||||
MessageHandler handler = new MessageHandler() {
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message<?> message) throws MessagingException {
|
||||
assertThat((String) message.getHeaders().get("name"), equalTo("foo"));
|
||||
assertThat(
|
||||
(String) message.getHeaders().get("string"),
|
||||
equalTo("public abstract void org.springframework.integration.gateway.GatewayInterfaceTests$Foo.foo(java.lang.String)"));
|
||||
assertThat((Method) message.getHeaders().get("object"), equalTo(fooMethod));
|
||||
assertThat((String) message.getPayload(), equalTo("hello"));
|
||||
called.set(true);
|
||||
}
|
||||
};
|
||||
channel.subscribe(handler);
|
||||
Bar bar = ac.getBean(Bar.class);
|
||||
bar.foo("hello");
|
||||
verify(handler, times(1)).handleMessage(Mockito.any(Message.class));
|
||||
assertTrue(called.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithServiceAnnotatedMethod(){
|
||||
public void testWithServiceSuperclassAnnotatedMethodOverridePE() throws Exception {
|
||||
ApplicationContext ac = new ClassPathXmlApplicationContext("GatewayInterfaceTests2-context.xml", this.getClass());
|
||||
DirectChannel channel = ac.getBean("requestChannelFoo", DirectChannel.class);
|
||||
final Method fooMethod = Foo.class.getMethod("foo", String.class);
|
||||
final AtomicBoolean called = new AtomicBoolean();
|
||||
MessageHandler handler = new MessageHandler() {
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message<?> message) throws MessagingException {
|
||||
assertThat((String) message.getHeaders().get("name"), equalTo("foo"));
|
||||
assertThat(
|
||||
(String) message.getHeaders().get("string"),
|
||||
equalTo("public abstract void org.springframework.integration.gateway.GatewayInterfaceTests$Foo.foo(java.lang.String)"));
|
||||
assertThat((Method) message.getHeaders().get("object"), equalTo(fooMethod));
|
||||
assertThat((String) message.getPayload(), equalTo("foo"));
|
||||
called.set(true);
|
||||
}
|
||||
};
|
||||
channel.subscribe(handler);
|
||||
Bar bar = ac.getBean(Bar.class);
|
||||
bar.foo("hello");
|
||||
assertTrue(called.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithServiceAnnotatedMethod() {
|
||||
ApplicationContext ac = new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", this.getClass());
|
||||
DirectChannel channel = ac.getBean("requestChannelBar", DirectChannel.class);
|
||||
MessageHandler handler = mock(MessageHandler.class);
|
||||
@@ -63,18 +110,57 @@ public class GatewayInterfaceTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithServiceSuperclassUnAnnotatedMethod(){
|
||||
public void testWithServiceSuperclassUnAnnotatedMethod() throws Exception {
|
||||
ApplicationContext ac = new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", this.getClass());
|
||||
DirectChannel channel = ac.getBean("requestChannelBaz", DirectChannel.class);
|
||||
MessageHandler handler = mock(MessageHandler.class);
|
||||
final Method bazMethod = Foo.class.getMethod("baz", String.class);
|
||||
final AtomicBoolean called = new AtomicBoolean();
|
||||
MessageHandler handler = new MessageHandler() {
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message<?> message) throws MessagingException {
|
||||
assertThat((String) message.getHeaders().get("name"), equalTo("overrideGlobal"));
|
||||
assertThat(
|
||||
(String) message.getHeaders().get("string"),
|
||||
equalTo("public abstract void org.springframework.integration.gateway.GatewayInterfaceTests$Foo.baz(java.lang.String)"));
|
||||
assertThat((Method) message.getHeaders().get("object"), equalTo(bazMethod));
|
||||
assertThat((String) message.getPayload(), equalTo("hello"));
|
||||
called.set(true);
|
||||
}
|
||||
};
|
||||
channel.subscribe(handler);
|
||||
Bar bar = ac.getBean(Bar.class);
|
||||
bar.baz("hello");
|
||||
verify(handler, times(1)).handleMessage(Mockito.any(Message.class));
|
||||
assertTrue(called.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithServiceCastAsSuperclassAnnotatedMethod(){
|
||||
public void testWithServiceUnAnnotatedMethodGlobalHeaderDoesntOverride() throws Exception {
|
||||
ApplicationContext ac = new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", this.getClass());
|
||||
DirectChannel channel = ac.getBean("requestChannelBaz", DirectChannel.class);
|
||||
final Method quxMethod = Bar.class.getMethod("qux", String.class, String.class);
|
||||
final AtomicBoolean called = new AtomicBoolean();
|
||||
MessageHandler handler = new MessageHandler() {
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message<?> message) throws MessagingException {
|
||||
assertThat((String) message.getHeaders().get("name"), equalTo("arg1"));
|
||||
assertThat(
|
||||
(String) message.getHeaders().get("string"),
|
||||
equalTo("public abstract void org.springframework.integration.gateway.GatewayInterfaceTests$Bar.qux(java.lang.String,java.lang.String)"));
|
||||
assertThat((Method) message.getHeaders().get("object"), equalTo(quxMethod));
|
||||
assertThat((String) message.getPayload(), equalTo("hello"));
|
||||
called.set(true);
|
||||
}
|
||||
};
|
||||
channel.subscribe(handler);
|
||||
Bar bar = ac.getBean(Bar.class);
|
||||
bar.qux("hello", "arg1");
|
||||
assertTrue(called.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithServiceCastAsSuperclassAnnotatedMethod() {
|
||||
ApplicationContext ac = new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", this.getClass());
|
||||
DirectChannel channel = ac.getBean("requestChannelFoo", DirectChannel.class);
|
||||
MessageHandler handler = mock(MessageHandler.class);
|
||||
@@ -85,7 +171,7 @@ public class GatewayInterfaceTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithServiceCastAsSuperclassUnAnnotatedMethod(){
|
||||
public void testWithServiceCastAsSuperclassUnAnnotatedMethod() {
|
||||
ApplicationContext ac = new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", this.getClass());
|
||||
DirectChannel channel = ac.getBean("requestChannelBaz", DirectChannel.class);
|
||||
MessageHandler handler = mock(MessageHandler.class);
|
||||
@@ -96,7 +182,7 @@ public class GatewayInterfaceTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithServiceHashcode() throws Exception{
|
||||
public void testWithServiceHashcode() throws Exception {
|
||||
ApplicationContext ac = new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", this.getClass());
|
||||
DirectChannel channel = ac.getBean("requestChannelBaz", DirectChannel.class);
|
||||
MessageHandler handler = mock(MessageHandler.class);
|
||||
@@ -107,7 +193,7 @@ public class GatewayInterfaceTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithServiceToString(){
|
||||
public void testWithServiceToString() {
|
||||
ApplicationContext ac = new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", this.getClass());
|
||||
DirectChannel channel = ac.getBean("requestChannelBaz", DirectChannel.class);
|
||||
MessageHandler handler = mock(MessageHandler.class);
|
||||
@@ -118,7 +204,7 @@ public class GatewayInterfaceTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithServiceEquals() throws Exception{
|
||||
public void testWithServiceEquals() throws Exception {
|
||||
ApplicationContext ac = new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", this.getClass());
|
||||
DirectChannel channel = ac.getBean("requestChannelBaz", DirectChannel.class);
|
||||
MessageHandler handler = mock(MessageHandler.class);
|
||||
@@ -137,7 +223,7 @@ public class GatewayInterfaceTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithServiceGetClass(){
|
||||
public void testWithServiceGetClass() {
|
||||
ApplicationContext ac = new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", this.getClass());
|
||||
DirectChannel channel = ac.getBean("requestChannelBaz", DirectChannel.class);
|
||||
MessageHandler handler = mock(MessageHandler.class);
|
||||
@@ -160,9 +246,11 @@ public class GatewayInterfaceTests {
|
||||
public void baz(String payload);
|
||||
}
|
||||
|
||||
public static interface Bar extends Foo{
|
||||
public static interface Bar extends Foo {
|
||||
@Gateway(requestChannel="requestChannelBar")
|
||||
public void bar(String payload);
|
||||
|
||||
public void qux(String payload, @Header("name") String nameHeader);
|
||||
}
|
||||
|
||||
public static class NotAnInterface {
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
<?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"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd">
|
||||
|
||||
<int:gateway id="sampleGateway"
|
||||
service-interface="org.springframework.integration.gateway.GatewayInterfaceTests.Bar"
|
||||
default-request-channel="requestChannelBaz" default-payload-expression="'foo'">
|
||||
<int:default-header name="name" expression="#gatewayMethod.name"/>
|
||||
<int:default-header name="string" expression="#gatewayMethod.toString()"/>
|
||||
<int:default-header name="object" expression="#gatewayMethod"/>
|
||||
<int:method name="baz">
|
||||
<int:header name="name" value="overrideGlobal"/>
|
||||
</int:method>
|
||||
</int:gateway>
|
||||
|
||||
<int:channel id="requestChannelFoo"/>
|
||||
<int:channel id="requestChannelBar"/>
|
||||
<int:channel id="requestChannelBaz"/>
|
||||
|
||||
</beans>
|
||||
@@ -17,6 +17,7 @@ package org.springframework.integration.file.config;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.integration.config.ExpressionFactoryBean;
|
||||
@@ -53,7 +54,12 @@ public abstract class AbstractRemoteFileOutboundGatewayParser extends AbstractCo
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "reply-channel", "outputChannel");
|
||||
this.configureFilter(builder, element, parserContext);
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "remote-file-separator");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "local-directory");
|
||||
|
||||
BeanDefinition localDirExpressionDef = IntegrationNamespaceUtils
|
||||
.createExpressionDefinitionFromValueOrExpression("local-directory", "local-directory-expression",
|
||||
parserContext, element, false);
|
||||
builder.addPropertyValue("localDirectoryExpression", localDirExpressionDef);
|
||||
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "auto-create-local-directory");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "order");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "rename-expression");
|
||||
|
||||
@@ -31,6 +31,7 @@ import java.util.Set;
|
||||
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.common.LiteralExpression;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.integration.expression.ExpressionUtils;
|
||||
import org.springframework.integration.file.FileHeaders;
|
||||
@@ -65,22 +66,27 @@ public abstract class AbstractRemoteFileOutboundGateway<F> extends AbstractReply
|
||||
* Enumeration of commands supported by the gateways.
|
||||
*/
|
||||
public static enum Command {
|
||||
|
||||
/**
|
||||
* List remote files.
|
||||
*/
|
||||
LS("ls"),
|
||||
|
||||
/**
|
||||
* Retrieve a remote file.
|
||||
*/
|
||||
GET("get"),
|
||||
|
||||
/**
|
||||
* Remove a remote file (path - including wildcards).
|
||||
*/
|
||||
RM("rm"),
|
||||
|
||||
/**
|
||||
* Retrieve multiple files matching a wildcard path.
|
||||
*/
|
||||
MGET("mget"),
|
||||
|
||||
/**
|
||||
* Move (rename) a remote file.
|
||||
*/
|
||||
@@ -111,34 +117,46 @@ public abstract class AbstractRemoteFileOutboundGateway<F> extends AbstractReply
|
||||
*
|
||||
*/
|
||||
public static enum Option {
|
||||
|
||||
/**
|
||||
* Don't return full file information; just the name (ls).
|
||||
*/
|
||||
NAME_ONLY("-1"),
|
||||
|
||||
/**
|
||||
* Include directories {@code .} and {@code ..} in the results (ls).
|
||||
* Include files beginning with {@code .}, including directories {@code .} and {@code ..} in the results (ls).
|
||||
*/
|
||||
ALL("-a"),
|
||||
|
||||
/**
|
||||
* Do not sort the results (ls with NAME_ONLY).
|
||||
*/
|
||||
NOSORT("-f"),
|
||||
|
||||
/**
|
||||
* Include directories in the results (ls).
|
||||
*/
|
||||
SUBDIRS("-dirs"),
|
||||
|
||||
/**
|
||||
* Include links in the results (ls).
|
||||
*/
|
||||
LINKS("-links"),
|
||||
|
||||
/**
|
||||
* Preserve the server timestamp (get, mget).
|
||||
*/
|
||||
PRESERVE_TIMESTAMP("-P"),
|
||||
|
||||
/**
|
||||
* Throw an exception if no files returned (mget).
|
||||
*/
|
||||
EXCEPTION_WHEN_EMPTY("-x");
|
||||
EXCEPTION_WHEN_EMPTY("-x"),
|
||||
|
||||
/**
|
||||
* Recursive (ls, mget)
|
||||
*/
|
||||
RECURSIVE("-R");
|
||||
|
||||
private String option;
|
||||
|
||||
@@ -170,7 +188,7 @@ public abstract class AbstractRemoteFileOutboundGateway<F> extends AbstractReply
|
||||
|
||||
private volatile String remoteFileSeparator = "/";
|
||||
|
||||
private volatile File localDirectory;
|
||||
private volatile Expression localDirectoryExpression;
|
||||
|
||||
private volatile boolean autoCreateLocalDirectory = true;
|
||||
|
||||
@@ -225,7 +243,13 @@ public abstract class AbstractRemoteFileOutboundGateway<F> extends AbstractReply
|
||||
* @param localDirectory the localDirectory to set
|
||||
*/
|
||||
public void setLocalDirectory(File localDirectory) {
|
||||
this.localDirectory = localDirectory;
|
||||
if (localDirectory != null) {
|
||||
this.localDirectoryExpression = new LiteralExpression(localDirectory.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
|
||||
public void setLocalDirectoryExpression(Expression localDirectoryExpression) {
|
||||
this.localDirectoryExpression = localDirectoryExpression;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -265,35 +289,43 @@ public abstract class AbstractRemoteFileOutboundGateway<F> extends AbstractReply
|
||||
protected void onInit() {
|
||||
super.onInit();
|
||||
Assert.notNull(this.command, "command must not be null");
|
||||
if (Command.RM.equals(this.command) || Command.MGET.equals(this.command) ||
|
||||
if (Command.RM.equals(this.command) ||
|
||||
Command.GET.equals(this.command)) {
|
||||
Assert.isNull(this.filter, "Filters are not supported with the rm, get, and mget commands");
|
||||
Assert.isNull(this.filter, "Filters are not supported with the rm and get commands");
|
||||
}
|
||||
if (Command.GET.equals(this.command)
|
||||
|| Command.MGET.equals(this.command)) {
|
||||
Assert.notNull(this.localDirectory, "localDirectory must not be null");
|
||||
try {
|
||||
if (!this.localDirectory.exists()) {
|
||||
if (this.autoCreateLocalDirectory) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("The '" + this.localDirectory + "' directory doesn't exist; Will create.");
|
||||
Assert.notNull(this.localDirectoryExpression, "localDirectory must not be null");
|
||||
if (this.localDirectoryExpression instanceof LiteralExpression) {
|
||||
File localDirectory = new File(this.localDirectoryExpression.getExpressionString());
|
||||
try {
|
||||
if (!localDirectory.exists()) {
|
||||
if (this.autoCreateLocalDirectory) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("The '" + localDirectory + "' directory doesn't exist; Will create.");
|
||||
}
|
||||
if (!localDirectory.mkdirs()) {
|
||||
throw new IOException("Failed to make local directory: " + localDirectory);
|
||||
}
|
||||
}
|
||||
if (!this.localDirectory.mkdirs()) {
|
||||
throw new IOException("Failed to make local directory: " + this.localDirectory);
|
||||
else {
|
||||
throw new FileNotFoundException(localDirectory.getName());
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new FileNotFoundException(this.localDirectory.getName());
|
||||
}
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
throw e;
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new MessagingException(
|
||||
"Failure during initialization of: " + this.getComponentType(), e);
|
||||
}
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
throw e;
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new MessagingException(
|
||||
"Failure during initialization of: " + this.getComponentType(), e);
|
||||
}
|
||||
}
|
||||
if (Command.MGET.equals(this.command)) {
|
||||
Assert.isTrue(!(this.options.contains(Option.SUBDIRS)),
|
||||
"Cannot use " + Option.SUBDIRS.toString() + " when using 'mget' use " + Option.RECURSIVE.toString() +
|
||||
" to obtain files in subdirectories");
|
||||
}
|
||||
if (this.getBeanFactory() != null) {
|
||||
this.fileNameProcessor.setBeanFactory(this.getBeanFactory());
|
||||
@@ -341,12 +373,9 @@ public abstract class AbstractRemoteFileOutboundGateway<F> extends AbstractReply
|
||||
|
||||
private Object doGet(Message<?> requestMessage, Session<F> session) throws IOException {
|
||||
String remoteFilePath = this.fileNameProcessor.processMessage(requestMessage);
|
||||
String remoteFilename = getRemoteFilename(remoteFilePath);
|
||||
String remoteDir = remoteFilePath.substring(0, remoteFilePath.indexOf(remoteFilename));
|
||||
if (remoteDir.length() == 0) {
|
||||
remoteDir = this.remoteFileSeparator;
|
||||
}
|
||||
File payload = get(requestMessage, session, remoteFilePath, remoteFilename, true);
|
||||
String remoteFilename = this.getRemoteFilename(remoteFilePath);
|
||||
String remoteDir = this.getRemoteDirectory(remoteFilePath, remoteFilename);
|
||||
File payload = this.get(requestMessage, session, remoteDir, remoteFilePath, remoteFilename, true);
|
||||
return MessageBuilder.withPayload(payload)
|
||||
.setHeader(FileHeaders.REMOTE_DIRECTORY, remoteDir)
|
||||
.setHeader(FileHeaders.REMOTE_FILE, remoteFilename)
|
||||
@@ -355,12 +384,9 @@ public abstract class AbstractRemoteFileOutboundGateway<F> extends AbstractReply
|
||||
|
||||
private Object doMget(Message<?> requestMessage, Session<F> session) throws IOException {
|
||||
String remoteFilePath = this.fileNameProcessor.processMessage(requestMessage);
|
||||
String remoteFilename = getRemoteFilename(remoteFilePath);
|
||||
String remoteDir = remoteFilePath.substring(0, remoteFilePath.indexOf(remoteFilename));
|
||||
if (remoteDir.length() == 0) {
|
||||
remoteDir = this.remoteFileSeparator;
|
||||
}
|
||||
List<File> payload = mGet(requestMessage, session, remoteDir, remoteFilename);
|
||||
String remoteFilename = this.getRemoteFilename(remoteFilePath);
|
||||
String remoteDir = this.getRemoteDirectory(remoteFilePath, remoteFilename);
|
||||
List<File> payload = this.mGet(requestMessage, session, remoteDir, remoteFilename);
|
||||
return MessageBuilder.withPayload(payload)
|
||||
.setHeader(FileHeaders.REMOTE_DIRECTORY, remoteDir)
|
||||
.setHeader(FileHeaders.REMOTE_FILE, remoteFilename)
|
||||
@@ -369,12 +395,9 @@ public abstract class AbstractRemoteFileOutboundGateway<F> extends AbstractReply
|
||||
|
||||
private Object doRm(Message<?> requestMessage, Session<F> session) throws IOException {
|
||||
String remoteFilePath = this.fileNameProcessor.processMessage(requestMessage);
|
||||
String remoteFilename = getRemoteFilename(remoteFilePath);
|
||||
String remoteDir = remoteFilePath.substring(0, remoteFilePath.indexOf(remoteFilename));
|
||||
if (remoteDir.length() == 0) {
|
||||
remoteDir = this.remoteFileSeparator;
|
||||
}
|
||||
boolean payload = rm(session, remoteFilePath);
|
||||
String remoteFilename = this.getRemoteFilename(remoteFilePath);
|
||||
String remoteDir = this.getRemoteDirectory(remoteFilePath, remoteFilename);
|
||||
boolean payload = this.rm(session, remoteFilePath);
|
||||
return MessageBuilder.withPayload(payload)
|
||||
.setHeader(FileHeaders.REMOTE_DIRECTORY, remoteDir)
|
||||
.setHeader(FileHeaders.REMOTE_FILE, remoteFilename)
|
||||
@@ -383,14 +406,12 @@ public abstract class AbstractRemoteFileOutboundGateway<F> extends AbstractReply
|
||||
|
||||
private Object doMv(Message<?> requestMessage, Session<F> session) throws IOException {
|
||||
String remoteFilePath = this.fileNameProcessor.processMessage(requestMessage);
|
||||
String remoteFilename = getRemoteFilename(remoteFilePath);
|
||||
String remoteDir = remoteFilePath.substring(0, remoteFilePath.indexOf(remoteFilename));
|
||||
String remoteFilename = this.getRemoteFilename(remoteFilePath);
|
||||
String remoteDir = this.getRemoteDirectory(remoteFilePath, remoteFilename);
|
||||
String remoteFileNewPath = this.renameProcessor.processMessage(requestMessage);
|
||||
Assert.hasLength(remoteFileNewPath, "New filename cannot be empty");
|
||||
if (remoteDir.length() == 0) {
|
||||
remoteDir = this.remoteFileSeparator;
|
||||
}
|
||||
mv(session, remoteFilePath, remoteFileNewPath);
|
||||
|
||||
this.mv(session, remoteFilePath, remoteFileNewPath);
|
||||
return MessageBuilder.withPayload(Boolean.TRUE)
|
||||
.setHeader(FileHeaders.REMOTE_DIRECTORY, remoteDir)
|
||||
.setHeader(FileHeaders.REMOTE_FILE, remoteFilename)
|
||||
@@ -399,21 +420,7 @@ public abstract class AbstractRemoteFileOutboundGateway<F> extends AbstractReply
|
||||
}
|
||||
|
||||
protected List<?> ls(Session<F> session, String dir) throws IOException {
|
||||
List<F> lsFiles = new ArrayList<F>();
|
||||
F[] files = session.list(dir);
|
||||
if (!ObjectUtils.isEmpty(files)) {
|
||||
Collection<F> filteredFiles = this.filterFiles(files);
|
||||
for (F file : filteredFiles) {
|
||||
if (file != null) {
|
||||
if (this.options.contains(Option.SUBDIRS) || !isDirectory(file)) {
|
||||
lsFiles.add(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
return lsFiles;
|
||||
}
|
||||
List<F> lsFiles = listFilesInRemoteDir(session, dir, "");
|
||||
if (!this.options.contains(Option.LINKS)) {
|
||||
purgeLinks(lsFiles);
|
||||
}
|
||||
@@ -442,6 +449,32 @@ public abstract class AbstractRemoteFileOutboundGateway<F> extends AbstractReply
|
||||
}
|
||||
}
|
||||
|
||||
private List<F> listFilesInRemoteDir(Session<F> session, String directory, String subDirectory) throws IOException {
|
||||
List<F> lsFiles = new ArrayList<F>();
|
||||
F[] files = session.list(directory + subDirectory);
|
||||
boolean recursion = this.options.contains(Option.RECURSIVE);
|
||||
if (!ObjectUtils.isEmpty(files)) {
|
||||
Collection<F> filteredFiles = this.filterFiles(files);
|
||||
for (F file : filteredFiles) {
|
||||
String fileName = this.getFilename(file);
|
||||
if (file != null) {
|
||||
if (this.options.contains(Option.SUBDIRS) || !this.isDirectory(file)) {
|
||||
if (recursion && StringUtils.hasText(subDirectory)) {
|
||||
lsFiles.add(enhanceNameWithSubDirectory(file, subDirectory));
|
||||
}
|
||||
else {
|
||||
lsFiles.add(file);
|
||||
}
|
||||
}
|
||||
if (recursion && this.isDirectory(file) && !(".".equals(fileName)) && !("..".equals(fileName))) {
|
||||
lsFiles.addAll(listFilesInRemoteDir(session, directory, subDirectory + fileName + this.remoteFileSeparator));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return lsFiles;
|
||||
}
|
||||
|
||||
protected final List<F> filterFiles(F[] files) {
|
||||
return (this.filter != null) ? this.filter.filterFiles(files) : Arrays.asList(files);
|
||||
}
|
||||
@@ -467,21 +500,25 @@ public abstract class AbstractRemoteFileOutboundGateway<F> extends AbstractReply
|
||||
/**
|
||||
* Copy a remote file to the configured local directory.
|
||||
*
|
||||
*
|
||||
* @param message
|
||||
* @param session
|
||||
* @param remoteFilePath
|
||||
* @throws IOException
|
||||
* @param remoteDir
|
||||
*@param remoteFilePath @throws IOException
|
||||
*/
|
||||
protected File get(Message<?> message, Session<F> session, String remoteFilePath, String remoteFilename, boolean lsFirst)
|
||||
protected File get(Message<?> message, Session<F> session, String remoteDir, String remoteFilePath, String remoteFilename, boolean lsFirst)
|
||||
throws IOException {
|
||||
F[] files = null;
|
||||
if (lsFirst) {
|
||||
files = session.list(remoteFilePath);
|
||||
if (files == null) {
|
||||
throw new MessagingException("Session returned null when listing " + remoteFilePath);
|
||||
}
|
||||
if (files.length != 1 || isDirectory(files[0]) || isLink(files[0])) {
|
||||
throw new MessagingException(remoteFilePath + " is not a file");
|
||||
}
|
||||
}
|
||||
File localFile = new File(this.localDirectory, this.generateLocalFileName(message, remoteFilename));
|
||||
File localFile = new File(this.generateLocalDirectory(message, remoteDir), this.generateLocalFileName(message, remoteFilename));
|
||||
if (!localFile.exists()) {
|
||||
String tempFileName = localFile.getAbsolutePath() + this.temporaryFileSuffix;
|
||||
File tempFile = new File(tempFileName);
|
||||
@@ -520,7 +557,23 @@ public abstract class AbstractRemoteFileOutboundGateway<F> extends AbstractReply
|
||||
|
||||
protected List<File> mGet(Message<?> message, Session<F> session, String remoteDirectory,
|
||||
String remoteFilename) throws IOException {
|
||||
String path = generateFullPath(remoteDirectory, remoteFilename);
|
||||
if (this.options.contains(Option.RECURSIVE)) {
|
||||
if (logger.isWarnEnabled() && !("*".equals(remoteFilename))) {
|
||||
logger.warn("File name pattern must be '*' when using recursion");
|
||||
}
|
||||
if (this.options.contains(Option.NAME_ONLY)) {
|
||||
this.options.remove(Option.NAME_ONLY);
|
||||
}
|
||||
return mGetWithRecursion(message, session, remoteDirectory, remoteFilename);
|
||||
}
|
||||
else {
|
||||
return mGetWithoutRecursion(message, session, remoteDirectory, remoteFilename);
|
||||
}
|
||||
}
|
||||
|
||||
private List<File> mGetWithoutRecursion(Message<?> message, Session<F> session, String remoteDirectory,
|
||||
String remoteFilename) throws IOException {
|
||||
String path = this.generateFullPath(remoteDirectory, remoteFilename);
|
||||
String[] fileNames = session.listNames(path);
|
||||
if (fileNames == null) {
|
||||
fileNames = new String[0];
|
||||
@@ -534,17 +587,50 @@ public abstract class AbstractRemoteFileOutboundGateway<F> extends AbstractReply
|
||||
File file;
|
||||
if (fileName.contains(this.remoteFileSeparator) &&
|
||||
fileName.startsWith(remoteDirectory)) { // the server returned the full path
|
||||
file = this.get(message, session, fileName,
|
||||
file = this.get(message, session, remoteDirectory, fileName,
|
||||
fileName.substring(fileName.lastIndexOf(this.remoteFileSeparator)), false);
|
||||
}
|
||||
else {
|
||||
file = this.get(message, session, generateFullPath(remoteDirectory, fileName), fileName, false);
|
||||
file = this.get(message, session, remoteDirectory,
|
||||
this.generateFullPath(remoteDirectory, fileName), fileName, false);
|
||||
}
|
||||
files.add(file);
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
private List<File> mGetWithRecursion(Message<?> message, Session<F> session, String remoteDirectory,
|
||||
String remoteFilename) throws IOException {
|
||||
List<File> files = new ArrayList<File>();
|
||||
@SuppressWarnings("unchecked")
|
||||
List<AbstractFileInfo<F>> fileNames = (List<AbstractFileInfo<F>>) this.ls(session, remoteDirectory);
|
||||
if (fileNames.size() == 0 && this.options.contains(Option.EXCEPTION_WHEN_EMPTY)) {
|
||||
throw new MessagingException("No files found at " + remoteDirectory
|
||||
+ " with pattern " + remoteFilename);
|
||||
}
|
||||
for (AbstractFileInfo<F> lsEntry : fileNames) {
|
||||
String fullFileName = remoteDirectory + this.getFilename(lsEntry);
|
||||
/*
|
||||
* With recursion, the filename might contain subdirectory information
|
||||
* normalize each file separately.
|
||||
*/
|
||||
String fileName = this.getRemoteFilename(fullFileName);
|
||||
String actualRemoteDirectory = this.getRemoteDirectory(fullFileName, fileName);
|
||||
File file = this.get(message, session, actualRemoteDirectory,
|
||||
fullFileName, fileName, false);
|
||||
files.add(file);
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
private String getRemoteDirectory(String remoteFilePath, String remoteFilename) {
|
||||
String remoteDir = remoteFilePath.substring(0, remoteFilePath.lastIndexOf(remoteFilename));
|
||||
if (remoteDir.length() == 0) {
|
||||
remoteDir = this.remoteFileSeparator;
|
||||
}
|
||||
return remoteDir;
|
||||
}
|
||||
|
||||
private String generateFullPath(String remoteDirectory, String remoteFilename) {
|
||||
String path;
|
||||
if (this.remoteFileSeparator.equals(remoteDirectory)) {
|
||||
@@ -588,6 +674,17 @@ public abstract class AbstractRemoteFileOutboundGateway<F> extends AbstractReply
|
||||
session.rename(remoteFilePath, remoteFileNewPath);
|
||||
}
|
||||
|
||||
private File generateLocalDirectory(Message<?> message, String remoteDirectory) {
|
||||
EvaluationContext evaluationContext = ExpressionUtils.createStandardEvaluationContext(this.getBeanFactory());
|
||||
evaluationContext.setVariable("remoteDirectory", remoteDirectory);
|
||||
// TODO Change 'desiredResultType' as 'File.class' after fix of SPR-10953.
|
||||
File localDir = new File(this.localDirectoryExpression.getValue(evaluationContext, message, String.class));
|
||||
if (!localDir.exists()) {
|
||||
Assert.isTrue(localDir.mkdirs(), "Failed to make local directory: " + localDir);
|
||||
}
|
||||
return localDir;
|
||||
}
|
||||
|
||||
private String generateLocalFileName(Message<?> message, String remoteFileName){
|
||||
if (this.localFilenameGeneratorExpression != null){
|
||||
EvaluationContext evaluationContext = ExpressionUtils.createStandardEvaluationContext(this.getBeanFactory());
|
||||
@@ -603,8 +700,11 @@ public abstract class AbstractRemoteFileOutboundGateway<F> extends AbstractReply
|
||||
|
||||
abstract protected String getFilename(F file);
|
||||
|
||||
abstract protected String getFilename(AbstractFileInfo<F> file);
|
||||
|
||||
abstract protected long getModified(F file);
|
||||
|
||||
abstract protected List<AbstractFileInfo<F>> asFileInfoList(Collection<F> files);
|
||||
|
||||
abstract protected F enhanceNameWithSubDirectory(F file, String directory);
|
||||
}
|
||||
|
||||
@@ -16,10 +16,13 @@
|
||||
|
||||
package org.springframework.integration.file.remote.handler;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
@@ -35,7 +38,6 @@ import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageDeliveryException;
|
||||
import org.springframework.messaging.MessagingException;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -67,8 +69,6 @@ public class FileTransferringMessageHandler<F> extends AbstractMessageHandler {
|
||||
|
||||
private volatile boolean fileNameGeneratorSet;
|
||||
|
||||
private volatile File temporaryDirectory = new File(System.getProperty("java.io.tmpdir"));
|
||||
|
||||
private volatile String charset = "UTF-8";
|
||||
|
||||
private volatile String remoteFileSeparator = "/";
|
||||
@@ -105,9 +105,11 @@ public class FileTransferringMessageHandler<F> extends AbstractMessageHandler {
|
||||
return this.temporaryFileSuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated This property is no longer used; byte[] and String payloads are written directly
|
||||
*/
|
||||
@Deprecated
|
||||
public void setTemporaryDirectory(File temporaryDirectory) {
|
||||
Assert.notNull(temporaryDirectory, "temporaryDirectory must not be null");
|
||||
this.temporaryDirectory = temporaryDirectory;
|
||||
}
|
||||
|
||||
protected boolean isUseTemporaryFileName() {
|
||||
@@ -158,81 +160,87 @@ public class FileTransferringMessageHandler<F> extends AbstractMessageHandler {
|
||||
|
||||
@Override
|
||||
protected void handleMessageInternal(Message<?> message) throws Exception {
|
||||
File file = this.redeemForStorableFile(message);
|
||||
if (file != null && file.exists()) {
|
||||
StreamHolder inputStreamHolder = this.payloadToInputStream(message);
|
||||
if (inputStreamHolder != null) {
|
||||
Session<F> session = this.sessionFactory.getSession();
|
||||
String fileName = inputStreamHolder.getName();
|
||||
try {
|
||||
String remoteDirectory = this.directoryExpressionProcessor.processMessage(message);
|
||||
String temporaryRemoteDirectory = remoteDirectory;
|
||||
if (this.temporaryDirectoryExpressionProcessor != null){
|
||||
temporaryRemoteDirectory = this.temporaryDirectoryExpressionProcessor.processMessage(message);
|
||||
}
|
||||
String fileName = this.fileNameGenerator.generateFileName(message);
|
||||
this.sendFileToRemoteDirectory(file, temporaryRemoteDirectory, remoteDirectory, fileName, session);
|
||||
fileName = this.fileNameGenerator.generateFileName(message);
|
||||
this.sendFileToRemoteDirectory(inputStreamHolder.getStream(), temporaryRemoteDirectory, remoteDirectory, fileName, session);
|
||||
}
|
||||
catch (FileNotFoundException e) {
|
||||
throw new MessageDeliveryException(message,
|
||||
"File [" + file + "] not found in local working directory; it was moved or deleted unexpectedly.", e);
|
||||
"File [" + inputStreamHolder.getName() + "] not found in local working directory; it was moved or deleted unexpectedly.", e);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new MessageDeliveryException(message,
|
||||
"Failed to transfer file [" + file + "] from local working directory to remote FTP directory.", e);
|
||||
"Failed to transfer file [" + inputStreamHolder.getName() + " -> " + fileName + "] from local directory to remote directory.", e);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new MessageDeliveryException(message,
|
||||
"Error handling message for file [" + file + "]", e);
|
||||
"Error handling message for file [" + inputStreamHolder.getName() + " -> " + fileName + "]", e);
|
||||
}
|
||||
finally {
|
||||
if (!(message.getPayload() instanceof File)) {
|
||||
// we created the File, so we need to delete it
|
||||
if (file.exists()) {
|
||||
try {
|
||||
file.delete();
|
||||
}
|
||||
catch (Throwable t) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
if (session != null) {
|
||||
session.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// A null holder means a File payload that does not exist.
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("File " + message.getPayload() + " does not exist");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private File redeemForStorableFile(Message<?> message) throws MessageDeliveryException {
|
||||
private StreamHolder payloadToInputStream(Message<?> message) throws MessageDeliveryException {
|
||||
try {
|
||||
Object payload = message.getPayload();
|
||||
File sendableFile = null;
|
||||
InputStream dataInputStream = null;
|
||||
String name = null;
|
||||
if (payload instanceof File) {
|
||||
sendableFile = (File) payload;
|
||||
File inputFile = (File) payload;
|
||||
if (inputFile.exists()) {
|
||||
dataInputStream = new BufferedInputStream(new FileInputStream(inputFile));
|
||||
name = inputFile.getAbsolutePath();
|
||||
}
|
||||
}
|
||||
else if (payload instanceof byte[] || payload instanceof String) {
|
||||
String tempFileName = this.fileNameGenerator.generateFileName(message) + ".tmp";
|
||||
sendableFile = new File(this.temporaryDirectory, tempFileName); // will only create temp file for String/byte[]
|
||||
byte[] bytes = null;
|
||||
if (payload instanceof String) {
|
||||
bytes = ((String) payload).getBytes(this.charset);
|
||||
name = "String payload";
|
||||
}
|
||||
else {
|
||||
bytes = (byte[]) payload;
|
||||
name = "byte[] payload";
|
||||
}
|
||||
FileCopyUtils.copy(bytes, sendableFile);
|
||||
dataInputStream = new ByteArrayInputStream(bytes);
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("Unsupported payload type. The only supported payloads are " +
|
||||
"java.io.File, java.lang.String, and byte[]");
|
||||
}
|
||||
return sendableFile;
|
||||
if (dataInputStream == null) {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
return new StreamHolder(dataInputStream, name);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new MessageDeliveryException(message, "Failed to create sendable file.", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void sendFileToRemoteDirectory(File file, String temporaryRemoteDirectory, String remoteDirectory, String fileName, Session<F> session)
|
||||
throws FileNotFoundException, IOException {
|
||||
private void sendFileToRemoteDirectory(InputStream inputStream, String temporaryRemoteDirectory,
|
||||
String remoteDirectory, String fileName, Session<F> session) throws FileNotFoundException, IOException {
|
||||
|
||||
remoteDirectory = this.normalizeDirectoryPath(remoteDirectory);
|
||||
temporaryRemoteDirectory = this.normalizeDirectoryPath(temporaryRemoteDirectory);
|
||||
@@ -253,9 +261,8 @@ public class FileTransferringMessageHandler<F> extends AbstractMessageHandler {
|
||||
}
|
||||
}
|
||||
|
||||
FileInputStream fileInputStream = new FileInputStream(file);
|
||||
try {
|
||||
session.write(fileInputStream, tempFilePath);
|
||||
session.write(inputStream, tempFilePath);
|
||||
// then rename it to its final name if necessary
|
||||
if (useTemporaryFileName){
|
||||
session.rename(tempFilePath, remoteFilePath);
|
||||
@@ -265,7 +272,7 @@ public class FileTransferringMessageHandler<F> extends AbstractMessageHandler {
|
||||
throw new MessagingException("Failed to write to '" + tempFilePath + "' while uploading the file", e);
|
||||
}
|
||||
finally {
|
||||
fileInputStream.close();
|
||||
inputStream.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -279,4 +286,25 @@ public class FileTransferringMessageHandler<F> extends AbstractMessageHandler {
|
||||
return directoryPath;
|
||||
}
|
||||
|
||||
private class StreamHolder {
|
||||
|
||||
private final InputStream stream;
|
||||
|
||||
private final String name;
|
||||
|
||||
private StreamHolder(InputStream stream, String name) {
|
||||
this.stream = stream;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public InputStream getStream() {
|
||||
return stream;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@ import java.util.List;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.Expression;
|
||||
@@ -90,8 +89,6 @@ public abstract class AbstractInboundFileSynchronizer<F> implements InboundFileS
|
||||
*/
|
||||
private volatile boolean deleteRemoteFiles;
|
||||
|
||||
private volatile BeanFactory beanFactory;
|
||||
|
||||
/**
|
||||
* Create a synchronizer with the {@link SessionFactory} used to acquire {@link Session} instances.
|
||||
*/
|
||||
|
||||
@@ -86,21 +86,6 @@ public class RemoteFileOutboundGatewayTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBadFilterMGet() throws Exception {
|
||||
SessionFactory sessionFactory = mock(SessionFactory.class);
|
||||
TestRemoteFileOutboundGateway gw = new TestRemoteFileOutboundGateway
|
||||
(sessionFactory, "mget", "payload");
|
||||
gw.setFilter(new TestPatternFilter(""));
|
||||
try {
|
||||
gw.onInit();
|
||||
fail("Exception expected");
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
assertTrue(e.getMessage().startsWith("Filters are not supported"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBadFilterRm() throws Exception {
|
||||
SessionFactory sessionFactory = mock(SessionFactory.class);
|
||||
@@ -389,9 +374,6 @@ public class RemoteFileOutboundGatewayTests {
|
||||
assertEquals("foo/bar", madeDirs.get(1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public TestLsEntry[] fileList() {
|
||||
TestLsEntry[] files = new TestLsEntry[6];
|
||||
files[0] = new TestLsEntry("f2", 123, false, false, 1234, "-r--r--r--");
|
||||
@@ -424,6 +406,83 @@ public class RemoteFileOutboundGatewayTests {
|
||||
out.getHeaders().get(FileHeaders.REMOTE_DIRECTORY));
|
||||
}
|
||||
|
||||
public TestLsEntry[] level1List() {
|
||||
return new TestLsEntry[] {
|
||||
new TestLsEntry("f1", 123, false, false, 1234, "-r--r--r--"),
|
||||
new TestLsEntry("d1", 0, true, false, 12345, "drw-r--r--"),
|
||||
new TestLsEntry("f2", 12345, false, false, 123456, "-rw-r--r--")
|
||||
};
|
||||
}
|
||||
|
||||
public TestLsEntry[] level2List() {
|
||||
return new TestLsEntry[] {
|
||||
new TestLsEntry("d2", 0, true, false, 12345, "drw-r--r--"),
|
||||
new TestLsEntry("f3", 12345, false, false, 123456, "-rw-r--r--")
|
||||
};
|
||||
}
|
||||
|
||||
public TestLsEntry[] level3List() {
|
||||
return new TestLsEntry[] {
|
||||
new TestLsEntry("f4", 12345, false, false, 123456, "-rw-r--r--")
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLs_f_R() throws Exception {
|
||||
SessionFactory sessionFactory = mock(SessionFactory.class);
|
||||
Session session = mock(Session.class);
|
||||
TestRemoteFileOutboundGateway gw = new TestRemoteFileOutboundGateway
|
||||
(sessionFactory, "ls", "payload");
|
||||
gw.setOptions("-f -R");
|
||||
gw.afterPropertiesSet();
|
||||
when(sessionFactory.getSession()).thenReturn(session);
|
||||
TestLsEntry[] level1 = level1List();
|
||||
TestLsEntry[] level2 = level2List();
|
||||
TestLsEntry[] level3 = level3List();
|
||||
when(session.list("testremote/x/")).thenReturn(level1);
|
||||
when(session.list("testremote/x/d1/")).thenReturn(level2);
|
||||
when(session.list("testremote/x/d1/d2/")).thenReturn(level3);
|
||||
@SuppressWarnings("unchecked")
|
||||
Message<List<TestLsEntry>> out = (Message<List<TestLsEntry>>) gw
|
||||
.handleRequestMessage(new GenericMessage<String>("testremote/x"));
|
||||
assertEquals(4, out.getPayload().size());
|
||||
assertEquals("f1", out.getPayload().get(0).getFilename());
|
||||
assertEquals("d1/d2/f4", out.getPayload().get(1).getFilename());
|
||||
assertEquals("d1/f3", out.getPayload().get(2).getFilename());
|
||||
assertEquals("f2", out.getPayload().get(3).getFilename());
|
||||
assertEquals("testremote/x/",
|
||||
out.getHeaders().get(FileHeaders.REMOTE_DIRECTORY));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLs_f_R_dirs() throws Exception {
|
||||
SessionFactory sessionFactory = mock(SessionFactory.class);
|
||||
Session session = mock(Session.class);
|
||||
TestRemoteFileOutboundGateway gw = new TestRemoteFileOutboundGateway
|
||||
(sessionFactory, "ls", "payload");
|
||||
gw.setOptions("-f -R -dirs");
|
||||
gw.afterPropertiesSet();
|
||||
when(sessionFactory.getSession()).thenReturn(session);
|
||||
TestLsEntry[] level1 = level1List();
|
||||
TestLsEntry[] level2 = level2List();
|
||||
TestLsEntry[] level3 = level3List();
|
||||
when(session.list("testremote/x/")).thenReturn(level1);
|
||||
when(session.list("testremote/x/d1/")).thenReturn(level2);
|
||||
when(session.list("testremote/x/d1/d2/")).thenReturn(level3);
|
||||
@SuppressWarnings("unchecked")
|
||||
Message<List<TestLsEntry>> out = (Message<List<TestLsEntry>>) gw
|
||||
.handleRequestMessage(new GenericMessage<String>("testremote/x"));
|
||||
assertEquals(6, out.getPayload().size());
|
||||
assertEquals("f1", out.getPayload().get(0).getFilename());
|
||||
assertEquals("d1", out.getPayload().get(1).getFilename());
|
||||
assertEquals("d1/d2", out.getPayload().get(2).getFilename());
|
||||
assertEquals("d1/d2/f4", out.getPayload().get(3).getFilename());
|
||||
assertEquals("d1/f3", out.getPayload().get(4).getFilename());
|
||||
assertEquals("f2", out.getPayload().get(5).getFilename());
|
||||
assertEquals("testremote/x/",
|
||||
out.getHeaders().get(FileHeaders.REMOTE_DIRECTORY));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLs_None() throws Exception {
|
||||
SessionFactory sessionFactory = mock(SessionFactory.class);
|
||||
@@ -775,6 +834,11 @@ class TestRemoteFileOutboundGateway extends AbstractRemoteFileOutboundGateway<Te
|
||||
return file.getFilename();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getFilename(AbstractFileInfo<TestLsEntry> file) {
|
||||
return file.getFilename();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long getModified(TestLsEntry file) {
|
||||
return file.getModified();
|
||||
@@ -786,18 +850,24 @@ class TestRemoteFileOutboundGateway extends AbstractRemoteFileOutboundGateway<Te
|
||||
return new ArrayList<AbstractFileInfo<TestLsEntry>>(files);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TestLsEntry enhanceNameWithSubDirectory(TestLsEntry file, String directory) {
|
||||
file.setFilename(directory + file.getFilename());
|
||||
return file;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class TestLsEntry extends AbstractFileInfo<TestLsEntry> {
|
||||
|
||||
private final String filename;
|
||||
private final int size;
|
||||
private volatile String filename;
|
||||
private final long size;
|
||||
private final boolean dir;
|
||||
private final boolean link;
|
||||
private final long modified;
|
||||
private final String permissions;
|
||||
|
||||
public TestLsEntry(String filename, int size, boolean dir, boolean link,
|
||||
public TestLsEntry(String filename, long size, boolean dir, boolean link,
|
||||
long modified, String permissions) {
|
||||
this.filename = filename;
|
||||
this.size = size;
|
||||
@@ -835,6 +905,10 @@ class TestLsEntry extends AbstractFileInfo<TestLsEntry> {
|
||||
return this;
|
||||
}
|
||||
|
||||
public void setFilename(String filename) {
|
||||
this.filename = filename;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class TestPatternFilter extends AbstractSimplePatternFileListFilter<TestLsEntry>{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-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.
|
||||
@@ -21,6 +21,7 @@ import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.net.ftp.FTPFile;
|
||||
|
||||
import org.springframework.integration.file.remote.AbstractFileInfo;
|
||||
import org.springframework.integration.file.remote.gateway.AbstractRemoteFileOutboundGateway;
|
||||
import org.springframework.integration.file.remote.session.SessionFactory;
|
||||
@@ -28,7 +29,7 @@ import org.springframework.integration.ftp.session.FtpFileInfo;
|
||||
|
||||
/**
|
||||
* Outbound Gateway for performing remote file operations via FTP/FTPS.
|
||||
*
|
||||
*
|
||||
* @author Gary Russell
|
||||
* @since 2.1
|
||||
*/
|
||||
@@ -54,6 +55,11 @@ public class FtpOutboundGateway extends AbstractRemoteFileOutboundGateway<FTPFil
|
||||
return file.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getFilename(AbstractFileInfo<FTPFile> file) {
|
||||
return file.getFilename();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long getModified(FTPFile file) {
|
||||
return file.getTimestamp().getTimeInMillis();
|
||||
@@ -69,4 +75,11 @@ public class FtpOutboundGateway extends AbstractRemoteFileOutboundGateway<FTPFil
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FTPFile enhanceNameWithSubDirectory(FTPFile file, String directory) {
|
||||
file.setName(directory + file.getName());
|
||||
return file;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -415,6 +415,23 @@
|
||||
Identifies directory path (e.g.,
|
||||
"/local/mytransfers") where file will be
|
||||
transferred TO.
|
||||
This attribute is mutually exclusive with 'local-directory-expression'.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="local-directory-expression" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Specifies SpEL expression to
|
||||
generate the directory path where file will be
|
||||
transferred TO, when using 'get' and 'mget' commands.
|
||||
The root object of the SpEL evaluation is the request Message,
|
||||
but the name of the source
|
||||
remote directory is also provided as the 'remoteDirectory' variable.
|
||||
For example, a valid expression might be:
|
||||
"'/local/' + #remoteDirectory.toUpperCase() + headers.foo".
|
||||
Only used with 'get' and 'mget' commands.
|
||||
This attribute is mutually exclusive with 'local-directory'.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
|
||||
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
* Copyright 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.integration.ftp;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.PreDestroy;
|
||||
|
||||
import org.apache.ftpserver.FtpServer;
|
||||
import org.apache.ftpserver.FtpServerFactory;
|
||||
import org.apache.ftpserver.ftplet.Authentication;
|
||||
import org.apache.ftpserver.ftplet.AuthenticationFailedException;
|
||||
import org.apache.ftpserver.ftplet.FtpException;
|
||||
import org.apache.ftpserver.ftplet.User;
|
||||
import org.apache.ftpserver.ftplet.UserManager;
|
||||
import org.apache.ftpserver.listener.ListenerFactory;
|
||||
import org.apache.ftpserver.usermanager.impl.BaseUser;
|
||||
import org.apache.ftpserver.usermanager.impl.ConcurrentLoginPermission;
|
||||
import org.apache.ftpserver.usermanager.impl.TransferRatePermission;
|
||||
import org.apache.ftpserver.usermanager.impl.WritePermission;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.integration.ftp.session.DefaultFtpSessionFactory;
|
||||
import org.springframework.integration.test.util.SocketUtils;
|
||||
|
||||
/**
|
||||
* Embedded FTP Server for test cases; exposes an associated session factory
|
||||
* as a @Bean.
|
||||
*
|
||||
* @author Artem Bilan
|
||||
* @author Gary Russell
|
||||
* @since 3.0
|
||||
*/
|
||||
@Configuration
|
||||
public class TesFtpServer {
|
||||
|
||||
private final int ftpPort = SocketUtils.findAvailableServerSocket();
|
||||
|
||||
private final TemporaryFolder ftpFolder;
|
||||
|
||||
private final TemporaryFolder localFolder;
|
||||
|
||||
private volatile File ftpRootFolder;
|
||||
|
||||
private volatile File sourceFtpDirectory;
|
||||
|
||||
private volatile File targetFtpDirectory;
|
||||
|
||||
private volatile File sourceLocalDirectory;
|
||||
|
||||
private volatile File targetLocalDirectory;
|
||||
|
||||
private volatile FtpServer server;
|
||||
|
||||
public TesFtpServer(final String root) {
|
||||
this.ftpFolder = new TemporaryFolder() {
|
||||
|
||||
@Override
|
||||
public void create() throws IOException {
|
||||
super.create();
|
||||
ftpRootFolder = this.newFolder(root);
|
||||
sourceFtpDirectory = new File(ftpRootFolder, "ftpSource");
|
||||
sourceFtpDirectory.mkdir();
|
||||
File file = new File(sourceFtpDirectory, "ftpSource1.txt");
|
||||
file.createNewFile();
|
||||
file = new File(sourceFtpDirectory, "ftpSource2.txt");
|
||||
file.createNewFile();
|
||||
|
||||
File subSourceFtpDirectory = new File(sourceFtpDirectory, "subFtpSource");
|
||||
subSourceFtpDirectory.mkdir();
|
||||
file = new File(subSourceFtpDirectory, "subFtpSource1.txt");
|
||||
file.createNewFile();
|
||||
|
||||
targetFtpDirectory = new File(ftpRootFolder, "ftpTarget");
|
||||
targetFtpDirectory.mkdirs();
|
||||
}
|
||||
};
|
||||
this.localFolder = new TemporaryFolder() {
|
||||
|
||||
@Override
|
||||
public void create() throws IOException {
|
||||
super.create();
|
||||
File rootFolder = this.newFolder(root);
|
||||
sourceLocalDirectory = new File(rootFolder, "localSource");
|
||||
sourceLocalDirectory.mkdirs();
|
||||
File file = new File(sourceLocalDirectory, "localSource1.txt");
|
||||
file.createNewFile();
|
||||
file = new File(sourceLocalDirectory, "localSource2.txt");
|
||||
file.createNewFile();
|
||||
|
||||
File subSourceLocalDirectory = new File(sourceLocalDirectory, "subLocalSource");
|
||||
subSourceLocalDirectory.mkdir();
|
||||
file = new File(subSourceLocalDirectory, "subLocalSource1.txt");
|
||||
file.createNewFile();
|
||||
|
||||
targetLocalDirectory = new File(rootFolder, "localTarget");
|
||||
targetLocalDirectory.mkdirs();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public File getSourceFtpDirectory() {
|
||||
return sourceFtpDirectory;
|
||||
}
|
||||
|
||||
public File getTargetFtpDirectory() {
|
||||
return targetFtpDirectory;
|
||||
}
|
||||
|
||||
public File getSourceLocalDirectory() {
|
||||
return sourceLocalDirectory;
|
||||
}
|
||||
|
||||
public File getTargetLocalDirectory() {
|
||||
return targetLocalDirectory;
|
||||
}
|
||||
|
||||
public String getTargetLocalDirectoryName() {
|
||||
return targetLocalDirectory.getAbsolutePath() + File.separator;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public DefaultFtpSessionFactory ftpSessionFactory() {
|
||||
DefaultFtpSessionFactory factory = new DefaultFtpSessionFactory();
|
||||
factory.setHost("localhost");
|
||||
factory.setPort(this.ftpPort);
|
||||
factory.setUsername("foo");
|
||||
factory.setPassword("foo");
|
||||
return factory;
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void before() throws Throwable {
|
||||
this.ftpFolder.create();
|
||||
this.localFolder.create();
|
||||
|
||||
FtpServerFactory serverFactory = new FtpServerFactory();
|
||||
serverFactory.setUserManager(new TestUserManager(this.ftpRootFolder.getAbsolutePath()));
|
||||
|
||||
ListenerFactory factory = new ListenerFactory();
|
||||
factory.setPort(ftpPort);
|
||||
serverFactory.addListener("default", factory.createListener());
|
||||
|
||||
server = serverFactory.createServer();
|
||||
server.start();
|
||||
}
|
||||
|
||||
|
||||
@PreDestroy
|
||||
public void after() {
|
||||
this.server.stop();
|
||||
this.ftpFolder.delete();
|
||||
this.localFolder.delete();
|
||||
}
|
||||
|
||||
|
||||
public static void recursiveDelete(File file) {
|
||||
File[] files = file.listFiles();
|
||||
if (files != null) {
|
||||
for (File each : files) {
|
||||
recursiveDelete(each);
|
||||
}
|
||||
}
|
||||
file.delete();
|
||||
}
|
||||
|
||||
|
||||
private class TestUserManager implements UserManager {
|
||||
|
||||
private final BaseUser testUser;
|
||||
|
||||
private TestUserManager(String homeDirectory) {
|
||||
this.testUser = new BaseUser();
|
||||
this.testUser.setAuthorities(Arrays.asList(new ConcurrentLoginPermission(1024, 1024),
|
||||
new WritePermission(),
|
||||
new TransferRatePermission(1024, 1024)));
|
||||
this.testUser.setHomeDirectory(homeDirectory);
|
||||
this.testUser.setName("TEST_USER");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public User getUserByName(String s) throws FtpException {
|
||||
return this.testUser;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getAllUserNames() throws FtpException {
|
||||
return new String[]{"TEST_USER"};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(String s) throws FtpException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(User user) throws FtpException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doesExist(String s) throws FtpException {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public User authenticate(Authentication authentication) throws AuthenticationFailedException {
|
||||
return this.testUser;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAdminName() throws FtpException {
|
||||
return "admin";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAdmin(String s) throws FtpException {
|
||||
return s.equals("admin");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,15 +17,16 @@
|
||||
package org.springframework.integration.ftp.config;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
@@ -71,7 +72,6 @@ public class FtpOutboundChannelAdapterParserTests {
|
||||
assertEquals("UTF-8", TestUtils.getPropertyValue(handler, "charset"));
|
||||
assertNotNull(TestUtils.getPropertyValue(handler, "directoryExpressionProcessor"));
|
||||
assertNotNull(TestUtils.getPropertyValue(handler, "temporaryDirectoryExpressionProcessor"));
|
||||
assertNotNull(TestUtils.getPropertyValue(handler, "temporaryDirectory"));
|
||||
Object sfProperty = TestUtils.getPropertyValue(handler, "sessionFactory");
|
||||
assertEquals(DefaultFtpSessionFactory.class, sfProperty.getClass());
|
||||
DefaultFtpSessionFactory sessionFactory = (DefaultFtpSessionFactory) sfProperty;
|
||||
|
||||
@@ -77,7 +77,7 @@ public class FtpOutboundGatewayParserTests {
|
||||
assertEquals("X", TestUtils.getPropertyValue(gateway, "remoteFileSeparator"));
|
||||
assertNotNull(TestUtils.getPropertyValue(gateway, "sessionFactory"));
|
||||
assertNotNull(TestUtils.getPropertyValue(gateway, "outputChannel"));
|
||||
assertEquals(new File("local-test-dir"), TestUtils.getPropertyValue(gateway, "localDirectory"));
|
||||
assertEquals("local-test-dir", TestUtils.getPropertyValue(gateway, "localDirectoryExpression.literalValue"));
|
||||
assertFalse((Boolean) TestUtils.getPropertyValue(gateway, "autoCreateLocalDirectory"));
|
||||
assertNotNull(TestUtils.getPropertyValue(gateway, "filter"));
|
||||
assertEquals(Command.LS, TestUtils.getPropertyValue(gateway, "command"));
|
||||
@@ -100,7 +100,7 @@ public class FtpOutboundGatewayParserTests {
|
||||
assertNotNull(TestUtils.getPropertyValue(gateway, "sessionFactory"));
|
||||
assertTrue(TestUtils.getPropertyValue(gateway, "sessionFactory") instanceof CachingSessionFactory);
|
||||
assertNotNull(TestUtils.getPropertyValue(gateway, "outputChannel"));
|
||||
assertEquals(new File("local-test-dir"), TestUtils.getPropertyValue(gateway, "localDirectory"));
|
||||
assertEquals("local-test-dir", TestUtils.getPropertyValue(gateway, "localDirectoryExpression.literalValue"));
|
||||
assertFalse((Boolean) TestUtils.getPropertyValue(gateway, "autoCreateLocalDirectory"));
|
||||
assertEquals(Command.GET, TestUtils.getPropertyValue(gateway, "command"));
|
||||
@SuppressWarnings("unchecked")
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
package org.springframework.integration.ftp.config;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import org.junit.Test;
|
||||
@@ -47,7 +46,6 @@ public class FtpsOutboundChannelAdapterParserTests {
|
||||
FileTransferringMessageHandler<?> handler = TestUtils.getPropertyValue(consumer, "handler", FileTransferringMessageHandler.class);
|
||||
assertEquals(ac.getBean("fileNameGenerator"), TestUtils.getPropertyValue(handler, "fileNameGenerator"));
|
||||
assertEquals("UTF-8", TestUtils.getPropertyValue(handler, "charset"));
|
||||
assertNotNull(TestUtils.getPropertyValue(handler, "temporaryDirectory"));
|
||||
DefaultFtpsSessionFactory sf = TestUtils.getPropertyValue(handler, "sessionFactory", DefaultFtpsSessionFactory.class);
|
||||
assertEquals("localhost", TestUtils.getPropertyValue(sf, "host"));
|
||||
assertEquals(22, TestUtils.getPropertyValue(sf, "port"));
|
||||
|
||||
@@ -18,8 +18,11 @@ package org.springframework.integration.ftp.outbound;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.io.File;
|
||||
@@ -31,7 +34,10 @@ import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.net.ftp.FTPClient;
|
||||
import org.apache.commons.net.ftp.FTPFile;
|
||||
import org.junit.Before;
|
||||
@@ -40,6 +46,7 @@ import org.mockito.Mockito;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
|
||||
import org.springframework.beans.DirectFieldAccessor;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
@@ -53,6 +60,7 @@ import org.springframework.integration.file.remote.handler.FileTransferringMessa
|
||||
import org.springframework.integration.ftp.session.AbstractFtpSessionFactory;
|
||||
import org.springframework.integration.message.GenericMessage;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
import org.springframework.integration.test.util.TestUtils;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
|
||||
/**
|
||||
@@ -92,8 +100,11 @@ public class FtpOutboundTests {
|
||||
});
|
||||
handler.setBeanFactory(mock(BeanFactory.class));
|
||||
handler.afterPropertiesSet();
|
||||
handler.handleMessage(new GenericMessage<String>("hello"));
|
||||
handler.handleMessage(new GenericMessage<String>("String data"));
|
||||
assertTrue(file.exists());
|
||||
byte[] inFile = FileCopyUtils.copyToByteArray(file);
|
||||
assertEquals("String data", new String(inFile));
|
||||
file.delete();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -112,8 +123,11 @@ public class FtpOutboundTests {
|
||||
});
|
||||
handler.setBeanFactory(mock(BeanFactory.class));
|
||||
handler.afterPropertiesSet();
|
||||
handler.handleMessage(new GenericMessage<byte[]>("hello".getBytes()));
|
||||
handler.handleMessage(new GenericMessage<byte[]>("byte[] data".getBytes()));
|
||||
assertTrue(file.exists());
|
||||
byte[] inFile = FileCopyUtils.copyToByteArray(file);
|
||||
assertEquals("byte[] data", new String(inFile));
|
||||
file.delete();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -141,6 +155,41 @@ public class FtpOutboundTests {
|
||||
assertTrue("destination file was not created", destFile.exists());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHandleMissingFileMessage() throws Exception {
|
||||
File targetDir = new File("remote-target-dir");
|
||||
assertTrue("target directory does not exist: " + targetDir.getName(), targetDir.exists());
|
||||
|
||||
FileTransferringMessageHandler<FTPFile> handler = new FileTransferringMessageHandler<FTPFile>(sessionFactory);
|
||||
handler.setRemoteDirectoryExpression(new LiteralExpression(targetDir.getName()));
|
||||
handler.setFileNameGenerator(new FileNameGenerator() {
|
||||
public String generateFileName(Message<?> message) {
|
||||
return ((File)message.getPayload()).getName() + ".test";
|
||||
}
|
||||
});
|
||||
handler.setBeanFactory(mock(BeanFactory.class));
|
||||
handler.afterPropertiesSet();
|
||||
|
||||
File srcFile = new File(UUID.randomUUID() + ".txt");
|
||||
|
||||
Log logger = spy(TestUtils.getPropertyValue(handler, "logger", Log.class));
|
||||
when(logger.isWarnEnabled()).thenReturn(true);
|
||||
final AtomicReference<String> logged = new AtomicReference<String>();
|
||||
doAnswer(new Answer<Object>(){
|
||||
|
||||
@Override
|
||||
public Object answer(InvocationOnMock invocation) throws Throwable {
|
||||
logged.set((String) invocation.getArguments()[0]);
|
||||
invocation.callRealMethod();
|
||||
return null;
|
||||
}
|
||||
}).when(logger).warn(Mockito.anyString());
|
||||
new DirectFieldAccessor(handler).setPropertyValue("logger", logger);
|
||||
handler.handleMessage(new GenericMessage<File>(srcFile));
|
||||
assertNotNull(logged.get());
|
||||
assertEquals("File " + srcFile.toString() + " does not exist", logged.get());
|
||||
}
|
||||
|
||||
@Test //INT-2275
|
||||
public void testFtpOutboundChannelAdapterInsideChain() throws Exception {
|
||||
File targetDir = new File("remote-target-dir");
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
<?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-ftp="http://www.springframework.org/schema/integration/ftp"
|
||||
xmlns:int="http://www.springframework.org/schema/integration"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/integration/ftp
|
||||
http://www.springframework.org/schema/integration/ftp/spring-integration-ftp.xsd
|
||||
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||
|
||||
<bean id="ftpServer" class="org.springframework.integration.ftp.TesFtpServer">
|
||||
<constructor-arg value="FtpServerOutboundTests"/>
|
||||
</bean>
|
||||
|
||||
<int:channel id="output">
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
|
||||
<int:channel id="inboundGet"/>
|
||||
|
||||
<int-ftp:outbound-gateway session-factory="ftpSessionFactory"
|
||||
request-channel="inboundGet"
|
||||
command="get"
|
||||
expression="payload"
|
||||
local-directory-expression="@ftpServer.targetLocalDirectoryName + #remoteDirectory.toUpperCase()"
|
||||
local-filename-generator-expression="#remoteFileName.replaceFirst('ftpSource', 'localTarget')"
|
||||
reply-channel="output"/>
|
||||
|
||||
<int:channel id="invalidDirExpression"/>
|
||||
|
||||
<int-ftp:outbound-gateway session-factory="ftpSessionFactory"
|
||||
request-channel="invalidDirExpression"
|
||||
command="get"
|
||||
expression="payload"
|
||||
local-directory-expression="T(java.io.File).separator + #remoteDirectory + '?:'"
|
||||
reply-channel="output"/>
|
||||
|
||||
<int:channel id="inboundMGet"/>
|
||||
|
||||
<int-ftp:outbound-gateway session-factory="ftpSessionFactory"
|
||||
request-channel="inboundMGet"
|
||||
command="mget"
|
||||
expression="payload"
|
||||
local-directory-expression="@ftpServer.targetLocalDirectoryName + #remoteDirectory"
|
||||
local-filename-generator-expression="#remoteFileName.replaceFirst('ftpSource', 'localTarget')"
|
||||
reply-channel="output"/>
|
||||
|
||||
<int:channel id="inboundMGetRecursive"/>
|
||||
|
||||
<int-ftp:outbound-gateway session-factory="ftpSessionFactory"
|
||||
request-channel="inboundMGetRecursive"
|
||||
command="mget"
|
||||
expression="payload"
|
||||
command-options="-R"
|
||||
local-directory-expression="@ftpServer.targetLocalDirectoryName + #remoteDirectory"
|
||||
local-filename-generator-expression="#remoteFileName.replaceFirst('ftpSource', 'localTarget')"
|
||||
reply-channel="output"/>
|
||||
|
||||
<int:channel id="inboundMGetRecursiveFiltered"/>
|
||||
|
||||
<int-ftp:outbound-gateway session-factory="ftpSessionFactory"
|
||||
request-channel="inboundMGetRecursiveFiltered"
|
||||
command="mget"
|
||||
expression="payload"
|
||||
command-options="-R"
|
||||
filename-regex="(subFtpSource|.*1.txt)"
|
||||
local-directory-expression="@ftpServer.targetLocalDirectoryName + #remoteDirectory"
|
||||
local-filename-generator-expression="#remoteFileName.replaceFirst('ftpSource', 'localTarget')"
|
||||
reply-channel="output"/>
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright 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.integration.ftp.outbound;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.channel.DirectChannel;
|
||||
import org.springframework.integration.core.PollableChannel;
|
||||
import org.springframework.integration.ftp.TesFtpServer;
|
||||
import org.springframework.integration.message.GenericMessage;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
/**
|
||||
* @author Artem Bilan
|
||||
* @since 3.0
|
||||
*/
|
||||
@ContextConfiguration
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
public class FtpServerOutboundTests {
|
||||
|
||||
@Autowired
|
||||
public TesFtpServer ftpServer;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel output;
|
||||
|
||||
@Autowired
|
||||
private DirectChannel inboundGet;
|
||||
|
||||
@Autowired
|
||||
private DirectChannel invalidDirExpression;
|
||||
|
||||
@Autowired
|
||||
private DirectChannel inboundMGet;
|
||||
|
||||
@Autowired
|
||||
private DirectChannel inboundMGetRecursive;
|
||||
|
||||
@Autowired
|
||||
private DirectChannel inboundMGetRecursiveFiltered;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
TesFtpServer.recursiveDelete(ftpServer.getTargetLocalDirectory());
|
||||
TesFtpServer.recursiveDelete(ftpServer.getTargetFtpDirectory());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInt2866LocalDirectoryExpressionGET() {
|
||||
String dir = "ftpSource/";
|
||||
this.inboundGet.send(new GenericMessage<Object>(dir + "ftpSource1.txt"));
|
||||
Message<?> result = this.output.receive(1000);
|
||||
assertNotNull(result);
|
||||
File localFile = (File) result.getPayload();
|
||||
assertThat(localFile.getPath().replaceAll(java.util.regex.Matcher.quoteReplacement(File.separator), "/"),
|
||||
Matchers.containsString(dir.toUpperCase()));
|
||||
|
||||
dir = "ftpSource/subFtpSource/";
|
||||
this.inboundGet.send(new GenericMessage<Object>(dir + "subFtpSource1.txt"));
|
||||
result = this.output.receive(1000);
|
||||
assertNotNull(result);
|
||||
localFile = (File) result.getPayload();
|
||||
assertThat(localFile.getPath().replaceAll(java.util.regex.Matcher.quoteReplacement(File.separator), "/"),
|
||||
Matchers.containsString(dir.toUpperCase()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInt2866InvalidLocalDirectoryExpression() {
|
||||
try {
|
||||
this.invalidDirExpression.send(new GenericMessage<Object>("/ftpSource/ftpSource1.txt"));
|
||||
fail("Exception expected.");
|
||||
}
|
||||
catch (Exception e) {
|
||||
Throwable cause = e.getCause();
|
||||
assertThat(cause, Matchers.instanceOf(IllegalArgumentException.class));
|
||||
assertThat(cause.getMessage(), Matchers.startsWith("Failed to make local directory"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testInt2866LocalDirectoryExpressionMGET() {
|
||||
String dir = "ftpSource/";
|
||||
this.inboundMGet.send(new GenericMessage<Object>(dir + "*.txt"));
|
||||
Message<?> result = this.output.receive(1000);
|
||||
assertNotNull(result);
|
||||
List<File> localFiles = (List<File>) result.getPayload();
|
||||
|
||||
for (File file : localFiles) {
|
||||
assertThat(file.getPath().replaceAll(java.util.regex.Matcher.quoteReplacement(File.separator), "/"),
|
||||
Matchers.containsString(dir));
|
||||
}
|
||||
|
||||
dir = "ftpSource/subFtpSource/";
|
||||
this.inboundMGet.send(new GenericMessage<Object>(dir + "*.txt"));
|
||||
result = this.output.receive(1000);
|
||||
assertNotNull(result);
|
||||
localFiles = (List<File>) result.getPayload();
|
||||
|
||||
for (File file : localFiles) {
|
||||
assertThat(file.getPath().replaceAll(java.util.regex.Matcher.quoteReplacement(File.separator), "/"),
|
||||
Matchers.containsString(dir));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testInt3172LocalDirectoryExpressionMGETRecursive() {
|
||||
String dir = "ftpSource/";
|
||||
this.inboundMGetRecursive.send(new GenericMessage<Object>(dir + "*"));
|
||||
Message<?> result = this.output.receive(1000);
|
||||
assertNotNull(result);
|
||||
List<File> localFiles = (List<File>) result.getPayload();
|
||||
assertEquals(3, localFiles.size());
|
||||
|
||||
for (File file : localFiles) {
|
||||
assertThat(file.getPath().replaceAll(java.util.regex.Matcher.quoteReplacement(File.separator), "/"),
|
||||
Matchers.containsString(dir));
|
||||
}
|
||||
assertThat(localFiles.get(2).getPath().replaceAll(java.util.regex.Matcher.quoteReplacement(File.separator), "/"),
|
||||
Matchers.containsString(dir + "subFtpSource"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testInt3172LocalDirectoryExpressionMGETRecursiveFiltered() {
|
||||
String dir = "ftpSource/";
|
||||
this.inboundMGetRecursiveFiltered.send(new GenericMessage<Object>(dir + "*"));
|
||||
Message<?> result = this.output.receive(1000);
|
||||
assertNotNull(result);
|
||||
List<File> localFiles = (List<File>) result.getPayload();
|
||||
// should have filtered ftpSource2.txt
|
||||
assertEquals(2, localFiles.size());
|
||||
|
||||
for (File file : localFiles) {
|
||||
assertThat(file.getPath().replaceAll(java.util.regex.Matcher.quoteReplacement(File.separator), "/"),
|
||||
Matchers.containsString(dir));
|
||||
}
|
||||
assertThat(localFiles.get(1).getPath().replaceAll(java.util.regex.Matcher.quoteReplacement(File.separator), "/"),
|
||||
Matchers.containsString(dir + "subFtpSource"));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -26,7 +26,7 @@ task generateSql {
|
||||
doLast {
|
||||
['hsqldb', 'h2', 'db2', 'derby', 'mysql', 'mysql-5_6_4',
|
||||
'oracle10g', 'postgresql', 'sqlserver', 'sybase'].each { dbType ->
|
||||
ant.vppcopy(todir: generatedResourcesDir, overwrite: 'true') {
|
||||
ant.vppcopy(todir: generatedResourcesDir) {
|
||||
config {
|
||||
context {
|
||||
property key: 'includes', value: 'src/main/sql'
|
||||
@@ -45,3 +45,7 @@ task generateSql {
|
||||
|
||||
// tie schema generation to the build lifecycle
|
||||
compileJava.dependsOn generateSql
|
||||
|
||||
task cleanSql (type: Delete) {
|
||||
delete fileTree(dir: 'src/main/resources/org/springframework/integration/jdbc').include('*.sql').exclude('config', 'store/channel')
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -17,64 +17,79 @@ package org.springframework.integration.redis.channel;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
|
||||
import org.springframework.data.redis.connection.RedisConnection;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
|
||||
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageHandler;
|
||||
import org.springframework.integration.message.GenericMessage;
|
||||
import org.springframework.integration.redis.rules.RedisAvailable;
|
||||
import org.springframework.integration.redis.rules.RedisAvailableTests;
|
||||
import org.springframework.integration.test.util.TestUtils;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageHandler;
|
||||
import org.springframework.messaging.MessagingException;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
/**
|
||||
* @author Oleg Zhurakousky
|
||||
* @author Gary Russell
|
||||
* @author Artem Bilan
|
||||
* @since 2.0
|
||||
*/
|
||||
public class SubscribableRedisChannelTests extends RedisAvailableTests{
|
||||
public class SubscribableRedisChannelTests extends RedisAvailableTests {
|
||||
|
||||
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void pubSubChanneTest() throws Exception{
|
||||
JedisConnectionFactory connectionFactory = new JedisConnectionFactory();
|
||||
connectionFactory.setPort(7379);
|
||||
connectionFactory.afterPropertiesSet();
|
||||
public void pubSubChannelTest() throws Exception{
|
||||
RedisConnectionFactory connectionFactory = this.getConnectionFactoryForTest();
|
||||
|
||||
SubscribableRedisChannel channel = new SubscribableRedisChannel(connectionFactory, "si.test.channel");
|
||||
channel.setBeanFactory(mock(BeanFactory.class));
|
||||
channel.afterPropertiesSet();
|
||||
channel.start();
|
||||
MessageHandler handler = mock(MessageHandler.class);
|
||||
|
||||
RedisConnection connection = TestUtils.getPropertyValue(channel, "container.subscriptionTask.connection",
|
||||
RedisConnection.class);
|
||||
|
||||
int n = 0;
|
||||
while (n++ < 100 && !connection.isSubscribed()) {
|
||||
Thread.sleep(100);
|
||||
}
|
||||
assertTrue(n < 100);
|
||||
|
||||
final CountDownLatch latch = new CountDownLatch(3);
|
||||
MessageHandler handler = new MessageHandler() {
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message<?> message) throws MessagingException {
|
||||
latch.countDown();
|
||||
}
|
||||
};
|
||||
channel.subscribe(handler);
|
||||
|
||||
channel.send(new GenericMessage<String>("1"));
|
||||
channel.send(new GenericMessage<String>("2"));
|
||||
channel.send(new GenericMessage<String>("3"));
|
||||
Thread.sleep(1000);
|
||||
verify(handler, times(3)).handleMessage(Mockito.any(Message.class));
|
||||
channel.stop();
|
||||
assertTrue(latch.await(5, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void dispatcherHasNoSubscribersTest() throws Exception{
|
||||
JedisConnectionFactory connectionFactory = new JedisConnectionFactory();
|
||||
connectionFactory.setPort(7379);
|
||||
connectionFactory.afterPropertiesSet();
|
||||
RedisConnectionFactory connectionFactory = this.getConnectionFactoryForTest();
|
||||
|
||||
SubscribableRedisChannel channel = new SubscribableRedisChannel(connectionFactory, "si.test.channel.no.subs");
|
||||
channel.setBeanName("dhnsChannel");
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
<int-redis:publish-subscribe-channel id="redisChannel" topic-name="si.test.topic"
|
||||
serializer="redisSerializer"/>
|
||||
|
||||
<bean id="redisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
|
||||
<property name="port" value="7379"/>
|
||||
<bean id="redisConnectionFactory" class="org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory">
|
||||
<property name="port" value="#{T(org.springframework.integration.redis.rules.RedisAvailableRule).REDIS_PORT}"/>
|
||||
</bean>
|
||||
|
||||
<bean id="redisSerializer" class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
|
||||
|
||||
@@ -17,11 +17,15 @@
|
||||
package org.springframework.integration.redis.config;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.serializer.RedisSerializer;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessagingException;
|
||||
@@ -36,6 +40,7 @@ import org.springframework.integration.test.util.TestUtils;
|
||||
* @author Oleg Zhurakousky
|
||||
* @author Gary Russell
|
||||
* @author Gunnar Hillert
|
||||
* @author Artem Bilan
|
||||
*/
|
||||
public class RedisChannelParserTests extends RedisAvailableTests{
|
||||
|
||||
@@ -44,8 +49,8 @@ public class RedisChannelParserTests extends RedisAvailableTests{
|
||||
public void testPubSubChannelConfig(){
|
||||
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("RedisChannelParserTests-context.xml", this.getClass());
|
||||
SubscribableChannel redisChannel = context.getBean("redisChannel", SubscribableChannel.class);
|
||||
JedisConnectionFactory connectionFactory =
|
||||
TestUtils.getPropertyValue(redisChannel, "connectionFactory", JedisConnectionFactory.class);
|
||||
RedisConnectionFactory connectionFactory =
|
||||
TestUtils.getPropertyValue(redisChannel, "connectionFactory", RedisConnectionFactory.class);
|
||||
RedisSerializer<?> redisSerializer = TestUtils.getPropertyValue(redisChannel, "serializer", RedisSerializer.class);
|
||||
assertEquals(connectionFactory, context.getBean("redisConnectionFactory"));
|
||||
assertEquals(redisSerializer, context.getBean("redisSerializer"));
|
||||
@@ -65,20 +70,17 @@ public class RedisChannelParserTests extends RedisAvailableTests{
|
||||
SubscribableChannel redisChannel = context.getBean("redisChannel", SubscribableChannel.class);
|
||||
final Message<?> m = new GenericMessage<String>("Hello Redis");
|
||||
|
||||
final Marker marker = Mockito.mock(Marker.class);
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
redisChannel.subscribe(new MessageHandler() {
|
||||
public void handleMessage(Message<?> message) throws MessagingException {
|
||||
assertEquals(m.getPayload(), message.getPayload());
|
||||
marker.mark();
|
||||
latch.countDown();
|
||||
}
|
||||
});
|
||||
redisChannel.send(m);
|
||||
Thread.sleep(1000);
|
||||
Mockito.verify(marker, Mockito.times(1)).mark();
|
||||
|
||||
assertTrue(latch.await(2, TimeUnit.SECONDS));
|
||||
context.stop();
|
||||
}
|
||||
|
||||
interface Marker {
|
||||
void mark();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
<int-redis:inbound-channel-adapter
|
||||
id="adapter" topics="foo, bar" channel="receiveChannel" error-channel="testErrorChannel"
|
||||
message-converter="testConverter"
|
||||
message-converter="testConverter"
|
||||
serializer="serializer"/>
|
||||
|
||||
<int:channel id="receiveChannel">
|
||||
@@ -17,8 +17,8 @@
|
||||
|
||||
<int:channel id="testErrorChannel" />
|
||||
|
||||
<bean id="redisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
|
||||
<property name="port" value="7379" />
|
||||
<bean id="redisConnectionFactory" class="org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory">
|
||||
<property name="port" value="#{T(org.springframework.integration.redis.rules.RedisAvailableRule).REDIS_PORT}"/>
|
||||
</bean>
|
||||
|
||||
<bean id="testConverter"
|
||||
@@ -27,7 +27,7 @@
|
||||
<int-redis:inbound-channel-adapter
|
||||
id="autoChannel" topics="foo, bar" error-channel="testErrorChannel"
|
||||
message-converter="testConverter" />
|
||||
|
||||
|
||||
<bean id="serializer" class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
|
||||
|
||||
<int:bridge input-channel="autoChannel" output-channel="nullChannel"/>
|
||||
|
||||
@@ -21,18 +21,19 @@ import static org.junit.Assert.assertSame;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.DirectFieldAccessor;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.integration.channel.QueueChannel;
|
||||
import org.springframework.integration.redis.inbound.RedisInboundChannelAdapter;
|
||||
import org.springframework.integration.redis.rules.RedisAvailable;
|
||||
import org.springframework.integration.redis.rules.RedisAvailableTests;
|
||||
import org.springframework.integration.support.converter.SimpleMessageConverter;
|
||||
import org.springframework.integration.test.util.TestUtils;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
@@ -44,7 +45,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
*/
|
||||
@ContextConfiguration
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
public class RedisInboundChannelAdapterParserTests extends RedisAvailableTests{
|
||||
public class RedisInboundChannelAdapterParserTests extends RedisAvailableTests {
|
||||
|
||||
@Autowired
|
||||
private ApplicationContext context;
|
||||
@@ -71,16 +72,15 @@ public class RedisInboundChannelAdapterParserTests extends RedisAvailableTests{
|
||||
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testInboundChannelAdapterMessaging() throws Exception{
|
||||
JedisConnectionFactory connectionFactory = new JedisConnectionFactory();
|
||||
connectionFactory.setPort(7379);
|
||||
connectionFactory.afterPropertiesSet();
|
||||
public void testInboundChannelAdapterMessaging() throws Exception {
|
||||
RedisConnectionFactory connectionFactory = this.getConnectionFactoryForTest();
|
||||
|
||||
connectionFactory.getConnection().publish("foo".getBytes(), "Hello Redis from foo".getBytes());
|
||||
Thread.sleep(1000);
|
||||
|
||||
QueueChannel receiveChannel = context.getBean("receiveChannel", QueueChannel.class);
|
||||
assertEquals("Hello Redis from foo", receiveChannel.receive(1000).getPayload());
|
||||
assertEquals("Hello Redis from foo", receiveChannel.receive(2000).getPayload());
|
||||
connectionFactory.getConnection().publish("bar".getBytes(), "Hello Redis from bar".getBytes());
|
||||
assertEquals("Hello Redis from bar", receiveChannel.receive(1000).getPayload());
|
||||
assertEquals("Hello Redis from bar", receiveChannel.receive(2000).getPayload());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -21,8 +21,8 @@
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
|
||||
<bean id="redisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
|
||||
<property name="port" value="7379"/>
|
||||
<bean id="redisConnectionFactory" class="org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory">
|
||||
<property name="port" value="#{T(org.springframework.integration.redis.rules.RedisAvailableRule).REDIS_PORT}"/>
|
||||
</bean>
|
||||
|
||||
<bean id="testConverter" class="org.springframework.integration.redis.config.RedisOutboundChannelAdapterParserTests$TestMessageConverter"/>
|
||||
@@ -30,7 +30,7 @@
|
||||
<int:chain input-channel="redisOutboudChain">
|
||||
<int-redis:outbound-channel-adapter topic="foo"/>
|
||||
</int:chain>
|
||||
|
||||
|
||||
<bean id="serializer" class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
|
||||
|
||||
</beans>
|
||||
|
||||
@@ -16,9 +16,8 @@
|
||||
<int:poller fixed-rate="2000" max-messages-per-poll="10"/>
|
||||
</int-redis:store-inbound-channel-adapter>
|
||||
|
||||
<bean id="redisConnectionFactory"
|
||||
class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
|
||||
<property name="port" value="7379" />
|
||||
<bean id="redisConnectionFactory" class="org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory">
|
||||
<property name="port" value="#{T(org.springframework.integration.redis.rules.RedisAvailableRule).REDIS_PORT}"/>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2007-2011 the original author or authors
|
||||
* Copyright 2007-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.
|
||||
@@ -16,11 +16,17 @@
|
||||
|
||||
package org.springframework.integration.redis.inbound;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.data.redis.connection.RedisConnection;
|
||||
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
|
||||
import org.springframework.messaging.Message;
|
||||
@@ -29,11 +35,6 @@ import org.springframework.integration.redis.rules.RedisAvailable;
|
||||
import org.springframework.integration.redis.rules.RedisAvailableTests;
|
||||
import org.springframework.integration.test.util.TestUtils;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
* @since 2.1
|
||||
@@ -42,7 +43,7 @@ public class RedisInboundChannelAdapterTests extends RedisAvailableTests{
|
||||
|
||||
private final Log logger = LogFactory.getLog(this.getClass());
|
||||
|
||||
@Test
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testRedisInboundChannelAdapter() throws Exception {
|
||||
for (int iteration = 0; iteration < 10; iteration ++) {
|
||||
@@ -55,9 +56,7 @@ public class RedisInboundChannelAdapterTests extends RedisAvailableTests{
|
||||
String redisChannelName = "testRedisInboundChannelAdapterChannel";
|
||||
QueueChannel channel = new QueueChannel();
|
||||
|
||||
JedisConnectionFactory connectionFactory = new JedisConnectionFactory();
|
||||
connectionFactory.setPort(7379);
|
||||
connectionFactory.afterPropertiesSet();
|
||||
RedisConnectionFactory connectionFactory = this.getConnectionFactoryForTest();
|
||||
|
||||
RedisInboundChannelAdapter adapter = new RedisInboundChannelAdapter(connectionFactory);
|
||||
adapter.setTopics("testRedisInboundChannelAdapterChannel");
|
||||
@@ -87,7 +86,6 @@ public class RedisInboundChannelAdapterTests extends RedisAvailableTests{
|
||||
assertEquals(numToTest, counter);
|
||||
adapter.stop();
|
||||
container.stop();
|
||||
connectionFactory.destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-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.
|
||||
@@ -19,11 +19,12 @@ package org.springframework.integration.redis.inbound;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.support.collections.RedisList;
|
||||
import org.springframework.data.redis.support.collections.RedisZSet;
|
||||
import org.springframework.messaging.Message;
|
||||
@@ -34,6 +35,7 @@ import org.springframework.integration.redis.rules.RedisAvailableTests;
|
||||
|
||||
/**
|
||||
* @author Oleg Zhurakousky
|
||||
* @author Artem Bilan
|
||||
* @since 2.2
|
||||
*/
|
||||
public class RedisStoreInboundChannelAdapterIntegrationTests extends RedisAvailableTests{
|
||||
@@ -42,7 +44,7 @@ public class RedisStoreInboundChannelAdapterIntegrationTests extends RedisAvaila
|
||||
@RedisAvailable
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testListInboundConfiguration() throws Exception{
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
this.prepareList(jcf);
|
||||
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("list-inbound-adapter.xml", this.getClass());
|
||||
SourcePollingChannelAdapter spca = context.getBean("listAdapter", SourcePollingChannelAdapter.class);
|
||||
@@ -64,7 +66,7 @@ public class RedisStoreInboundChannelAdapterIntegrationTests extends RedisAvaila
|
||||
@RedisAvailable
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testListInboundConfigurationWithSynchronization() throws Exception{
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
this.prepareList(jcf);
|
||||
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("list-inbound-adapter.xml", this.getClass());
|
||||
SourcePollingChannelAdapter spca = context.getBean("listAdapterWithSynchronization", SourcePollingChannelAdapter.class);
|
||||
@@ -87,7 +89,7 @@ public class RedisStoreInboundChannelAdapterIntegrationTests extends RedisAvaila
|
||||
@RedisAvailable
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testListInboundConfigurationWithSynchronizationAndTemplate() throws Exception{
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
this.prepareList(jcf);
|
||||
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("list-inbound-adapter.xml", this.getClass());
|
||||
SourcePollingChannelAdapter spca = context.getBean("listAdapterWithSynchronizationAndRedisTemplate", SourcePollingChannelAdapter.class);
|
||||
@@ -110,7 +112,7 @@ public class RedisStoreInboundChannelAdapterIntegrationTests extends RedisAvaila
|
||||
@RedisAvailable
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testZsetInboundConfiguration(){
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
this.prepareZset(jcf);
|
||||
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("zset-inbound-adapter.xml", this.getClass());
|
||||
SourcePollingChannelAdapter zsetAdapterNoScore =
|
||||
@@ -136,7 +138,7 @@ public class RedisStoreInboundChannelAdapterIntegrationTests extends RedisAvaila
|
||||
@RedisAvailable
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testZsetInboundConfigurationWithScoreRange(){
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
this.prepareZset(jcf);
|
||||
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("zset-inbound-adapter.xml", this.getClass());
|
||||
SourcePollingChannelAdapter zsetAdapterWithScoreRange =
|
||||
@@ -162,7 +164,7 @@ public class RedisStoreInboundChannelAdapterIntegrationTests extends RedisAvaila
|
||||
@RedisAvailable
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testZsetInboundConfigurationWithSingleScore(){
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
this.prepareZset(jcf);
|
||||
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("zset-inbound-adapter.xml", this.getClass());
|
||||
SourcePollingChannelAdapter zsetAdapterWithSingleScore =
|
||||
@@ -188,7 +190,7 @@ public class RedisStoreInboundChannelAdapterIntegrationTests extends RedisAvaila
|
||||
@RedisAvailable
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testZsetInboundConfigurationWithSingleScoreAndSynchronization() throws Exception{
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
this.prepareZset(jcf);
|
||||
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("zset-inbound-adapter.xml", this.getClass());
|
||||
SourcePollingChannelAdapter zsetAdapterWithSingleScoreAndSynchronization =
|
||||
@@ -199,31 +201,33 @@ public class RedisStoreInboundChannelAdapterIntegrationTests extends RedisAvaila
|
||||
|
||||
QueueChannel redisChannel = context.getBean("redisChannel", QueueChannel.class);
|
||||
QueueChannel otherRedisChannel = context.getBean("otherRedisChannel", QueueChannel.class);
|
||||
|
||||
// get all 13 presidents
|
||||
zsetAdapterNoScore.start();
|
||||
|
||||
Message<RedisZSet<Object>> message = (Message<RedisZSet<Object>>) redisChannel.receive(1000);
|
||||
assertNotNull(message);
|
||||
assertEquals(13, message.getPayload().size());
|
||||
|
||||
zsetAdapterNoScore.stop();
|
||||
Thread.sleep(1000);
|
||||
|
||||
// get only presidents for 18th century
|
||||
zsetAdapterWithSingleScoreAndSynchronization.start();
|
||||
|
||||
message = (Message<RedisZSet<Object>>) otherRedisChannel.receive(1000);
|
||||
assertNotNull(message);
|
||||
assertEquals(2, message.getPayload().rangeByScore(18, 18).size());
|
||||
zsetAdapterWithSingleScoreAndSynchronization.stop();
|
||||
Thread.sleep(1000);
|
||||
|
||||
// ... however other elements are still available 13-2=11
|
||||
zsetAdapterNoScore.start();
|
||||
message = (Message<RedisZSet<Object>>) redisChannel.receive(1000);
|
||||
assertNotNull(message);
|
||||
assertEquals(11, message.getPayload().size());
|
||||
|
||||
int n = 0;
|
||||
while(n++ < 100 && message.getPayload().size() != 11) {
|
||||
Thread.sleep(100);
|
||||
}
|
||||
assertTrue(n < 100);
|
||||
|
||||
zsetAdapterNoScore.stop();
|
||||
|
||||
context.close();
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
<int:transactional synchronization-factory="syncFactory"/>
|
||||
</int:poller>
|
||||
</int-redis:store-inbound-channel-adapter>
|
||||
|
||||
|
||||
<int-redis:store-inbound-channel-adapter id="listAdapterWithSynchronizationAndRollback"
|
||||
connection-factory="redisConnectionFactory"
|
||||
key-expression="'presidents'"
|
||||
@@ -35,7 +35,7 @@
|
||||
<int:transactional synchronization-factory="syncFactory"/>
|
||||
</int:poller>
|
||||
</int-redis:store-inbound-channel-adapter>
|
||||
|
||||
|
||||
<int:channel id="redisFailChannel"/>
|
||||
|
||||
<int-redis:store-inbound-channel-adapter id="listAdapterWithSynchronizationAndRedisTemplate"
|
||||
@@ -47,12 +47,12 @@
|
||||
<int:transactional synchronization-factory="syncFactory"/>
|
||||
</int:poller>
|
||||
</int-redis:store-inbound-channel-adapter>
|
||||
|
||||
|
||||
<int:transaction-synchronization-factory id="syncFactory">
|
||||
<int:after-commit expression="#resource.attributes['store'].rename('bar')"/>
|
||||
<int:after-rollback expression="#store.rename('baz')"/>
|
||||
</int:transaction-synchronization-factory>
|
||||
|
||||
|
||||
<int-redis:store-inbound-channel-adapter id="listAdapterWithSynchronizationBeforeCommit"
|
||||
redis-template="redisTemplate"
|
||||
key-expression="'presidents'"
|
||||
@@ -62,11 +62,11 @@
|
||||
<int:transactional synchronization-factory="syncFactory2"/>
|
||||
</int:poller>
|
||||
</int-redis:store-inbound-channel-adapter>
|
||||
|
||||
|
||||
<int:channel id="adapterErrors">
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
|
||||
|
||||
<int:transaction-synchronization-factory id="syncFactory2">
|
||||
<int:before-commit expression="5/0"/>
|
||||
</int:transaction-synchronization-factory>
|
||||
@@ -85,10 +85,10 @@
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
|
||||
<bean id="redisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
|
||||
<property name="port" value="7379"/>
|
||||
<bean id="redisConnectionFactory" class="org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory">
|
||||
<property name="port" value="#{T(org.springframework.integration.redis.rules.RedisAvailableRule).REDIS_PORT}"/>
|
||||
</bean>
|
||||
|
||||
|
||||
<bean id="transactionManager" class="org.springframework.integration.transaction.PseudoTransactionManager"/>
|
||||
|
||||
</beans>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
channel="redisChannel"
|
||||
auto-startup="false"
|
||||
collection-type="ZSET">
|
||||
<int:poller fixed-rate="1000" max-messages-per-poll="2"/>
|
||||
<int:poller fixed-rate="1000"/>
|
||||
</int-redis:store-inbound-channel-adapter>
|
||||
|
||||
<int-redis:store-inbound-channel-adapter id="zsetAdapterWithScoreRange"
|
||||
@@ -31,7 +31,7 @@
|
||||
channel="redisChannel"
|
||||
auto-startup="false"
|
||||
collection-type="ZSET">
|
||||
<int:poller fixed-rate="1000" max-messages-per-poll="2"/>
|
||||
<int:poller fixed-rate="1000"/>
|
||||
</int-redis:store-inbound-channel-adapter>
|
||||
|
||||
<int-redis:store-inbound-channel-adapter id="zsetAdapterWithSingleScoreAndSynchronization"
|
||||
@@ -40,11 +40,11 @@
|
||||
channel="otherRedisChannel"
|
||||
auto-startup="false"
|
||||
collection-type="ZSET">
|
||||
<int:poller fixed-rate="1000" max-messages-per-poll="2">
|
||||
<int:poller fixed-rate="1000">
|
||||
<int:transactional synchronization-factory="syncFactory"/>
|
||||
</int:poller>
|
||||
</int-redis:store-inbound-channel-adapter>
|
||||
|
||||
|
||||
<int:transaction-synchronization-factory id="syncFactory">
|
||||
<int:after-commit expression="payload.removeByScore(18, 18)"/>
|
||||
</int:transaction-synchronization-factory>
|
||||
@@ -57,10 +57,11 @@
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
|
||||
<bean id="redisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
|
||||
<property name="port" value="7379"/>
|
||||
<bean id="redisConnectionFactory"
|
||||
class="org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory">
|
||||
<property name="port" value="#{T(org.springframework.integration.redis.rules.RedisAvailableRule).REDIS_PORT}"/>
|
||||
</bean>
|
||||
|
||||
|
||||
<bean id="transactionManager" class="org.springframework.integration.transaction.PseudoTransactionManager"/>
|
||||
|
||||
</beans>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2007-2011 the original author or authors
|
||||
* Copyright 2007-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.
|
||||
@@ -16,12 +16,15 @@
|
||||
|
||||
package org.springframework.integration.redis.outbound;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
|
||||
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.listener.ChannelTopic;
|
||||
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
|
||||
import org.springframework.data.redis.listener.Topic;
|
||||
@@ -31,24 +34,20 @@ import org.springframework.integration.redis.rules.RedisAvailable;
|
||||
import org.springframework.integration.redis.rules.RedisAvailableTests;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
* @since 2.1
|
||||
*/
|
||||
public class RedisPublishingMessageHandlerTests extends RedisAvailableTests{
|
||||
public class RedisPublishingMessageHandlerTests extends RedisAvailableTests {
|
||||
|
||||
@Test
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testRedisPublishingMessageHandler() throws Exception {
|
||||
int numToTest = 10;
|
||||
String topic = "si.test.channel";
|
||||
final CountDownLatch latch = new CountDownLatch(numToTest);
|
||||
|
||||
JedisConnectionFactory connectionFactory = new JedisConnectionFactory();
|
||||
connectionFactory.setPort(7379);
|
||||
connectionFactory.afterPropertiesSet();
|
||||
RedisConnectionFactory connectionFactory = this.getConnectionFactoryForTest();
|
||||
|
||||
MessageListenerAdapter listener = new MessageListenerAdapter();
|
||||
listener.setDelegate(new Listener(latch));
|
||||
@@ -67,8 +66,7 @@ public class RedisPublishingMessageHandlerTests extends RedisAvailableTests{
|
||||
for (int i = 0; i < numToTest; i++) {
|
||||
handler.handleMessage(MessageBuilder.withPayload("test-" + i).build());
|
||||
}
|
||||
latch.await(3, TimeUnit.SECONDS);
|
||||
assertEquals(0, latch.getCount());
|
||||
assertTrue(latch.await(3, TimeUnit.SECONDS));
|
||||
container.stop();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2007-2012 the original author or authors
|
||||
* Copyright 2007-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.
|
||||
@@ -27,9 +27,9 @@ import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||
@@ -63,7 +63,7 @@ public class RedisStoreOutboundChannelAdapterIntegrationTests extends RedisAvail
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testListWithKeyAsHeader(){
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
|
||||
RedisList<String> redisList =
|
||||
new DefaultRedisList<String>("pepboys", this.initTemplate(jcf, new StringRedisTemplate()));
|
||||
@@ -84,7 +84,7 @@ public class RedisStoreOutboundChannelAdapterIntegrationTests extends RedisAvail
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testListWithKeyAsHeaderSimple(){
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
|
||||
StringRedisTemplate redisTemplate = new StringRedisTemplate();
|
||||
RedisList<String> redisList =
|
||||
@@ -103,7 +103,7 @@ public class RedisStoreOutboundChannelAdapterIntegrationTests extends RedisAvail
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testListWithProvidedKey(){
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisList<String> redisList =
|
||||
new DefaultRedisList<String>("pepboys", this.initTemplate(jcf, new StringRedisTemplate()));
|
||||
assertEquals(0, redisList.size());
|
||||
@@ -123,7 +123,7 @@ public class RedisStoreOutboundChannelAdapterIntegrationTests extends RedisAvail
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testZsetSimplePayloadIncrement(){
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
|
||||
StringRedisTemplate redisTemplate = new StringRedisTemplate();
|
||||
RedisZSet<String> redisZSet =
|
||||
@@ -148,7 +148,7 @@ public class RedisStoreOutboundChannelAdapterIntegrationTests extends RedisAvail
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testZsetSimplePayloadOverwrite(){
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
|
||||
StringRedisTemplate redisTemplate = new StringRedisTemplate();
|
||||
RedisZSet<String> redisZSet =
|
||||
@@ -176,7 +176,7 @@ public class RedisStoreOutboundChannelAdapterIntegrationTests extends RedisAvail
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testZsetSimplePayloadIncrementBy2(){
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
|
||||
StringRedisTemplate redisTemplate = new StringRedisTemplate();
|
||||
RedisZSet<String> redisZSet =
|
||||
@@ -204,7 +204,7 @@ public class RedisStoreOutboundChannelAdapterIntegrationTests extends RedisAvail
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testZsetSimplePayloadOverwriteWithHeaderScore(){
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
|
||||
StringRedisTemplate redisTemplate = new StringRedisTemplate();
|
||||
RedisZSet<String> redisZSet =
|
||||
@@ -233,7 +233,7 @@ public class RedisStoreOutboundChannelAdapterIntegrationTests extends RedisAvail
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testMapToZsetWithProvidedKey(){
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisZSet<String> redisZset =
|
||||
new DefaultRedisZSet<String>("presidents", this.initTemplate(jcf, new StringRedisTemplate()));
|
||||
assertEquals(0, redisZset.size());
|
||||
@@ -279,7 +279,7 @@ public class RedisStoreOutboundChannelAdapterIntegrationTests extends RedisAvail
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testMapToMapWithProvidedKey(){
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisMap<String, String> redisMap =
|
||||
new DefaultRedisMap<String, String>("pepboys",
|
||||
this.initTemplate(jcf, new StringRedisTemplate()));
|
||||
@@ -308,7 +308,7 @@ public class RedisStoreOutboundChannelAdapterIntegrationTests extends RedisAvail
|
||||
@Test(expected=MessageHandlingException.class) // map key is not provided
|
||||
@RedisAvailable
|
||||
public void testMapToMapAsSingleEntryWithKeyAsHeaderFail(){
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisMap<String, Map<String, String>> redisMap =
|
||||
new DefaultRedisMap<String, Map<String, String>>("pepboys",
|
||||
this.initTemplate(jcf, new RedisTemplate<String, Map<String, Map<String, String>>>()));
|
||||
@@ -330,7 +330,7 @@ public class RedisStoreOutboundChannelAdapterIntegrationTests extends RedisAvail
|
||||
@Test(expected=MessageHandlingException.class) // key is not provided
|
||||
@RedisAvailable
|
||||
public void testMapToMapNoKey(){
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisTemplate<String, Map<String, Map<String, String>>> redisTemplate = new RedisTemplate<String, Map<String, Map<String, String>>>();
|
||||
redisTemplate.setKeySerializer(new StringRedisSerializer());
|
||||
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
|
||||
@@ -354,7 +354,7 @@ public class RedisStoreOutboundChannelAdapterIntegrationTests extends RedisAvail
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testMapToMapAsSingleEntryWithKeyAsHeader(){
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisTemplate<String, Map<String, Map<String, String>>> redisTemplate = new RedisTemplate<String, Map<String, Map<String, String>>>();
|
||||
redisTemplate.setKeySerializer(new StringRedisSerializer());
|
||||
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
|
||||
@@ -384,7 +384,7 @@ public class RedisStoreOutboundChannelAdapterIntegrationTests extends RedisAvail
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testStoreSimpleStringInMap(){
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
StringRedisTemplate redisTemplate = new StringRedisTemplate();
|
||||
RedisMap<String, String> redisMap =
|
||||
new DefaultRedisMap<String, String>("bar",
|
||||
@@ -406,7 +406,7 @@ public class RedisStoreOutboundChannelAdapterIntegrationTests extends RedisAvail
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testSetWithKeyAsHeader(){
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisSet<String> redisSet =
|
||||
new DefaultRedisSet<String>("pepboys", this.initTemplate(jcf, new StringRedisTemplate()));
|
||||
assertEquals(0, redisSet.size());
|
||||
@@ -426,7 +426,7 @@ public class RedisStoreOutboundChannelAdapterIntegrationTests extends RedisAvail
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testSetWithKeyAsHeaderSimple(){
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
StringRedisTemplate redisTemplate = new StringRedisTemplate();
|
||||
RedisSet<String> redisSet =
|
||||
new DefaultRedisSet<String>("foo", this.initTemplate(jcf, redisTemplate));
|
||||
@@ -445,7 +445,7 @@ public class RedisStoreOutboundChannelAdapterIntegrationTests extends RedisAvail
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testSetWithKeyAsHeaderNotParsed(){
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisTemplate<String, String> redisTemplate = new RedisTemplate<String, String>();
|
||||
redisTemplate.setKeySerializer(new StringRedisSerializer());
|
||||
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
|
||||
@@ -468,7 +468,7 @@ public class RedisStoreOutboundChannelAdapterIntegrationTests extends RedisAvail
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testPojoIntoSet(){
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisSet<String> redisSet =
|
||||
new DefaultRedisSet<String>("pepboys", this.initTemplate(jcf, new StringRedisTemplate()));
|
||||
assertEquals(0, redisSet.size());
|
||||
@@ -485,7 +485,7 @@ public class RedisStoreOutboundChannelAdapterIntegrationTests extends RedisAvail
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testProperties(){
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisProperties redisProperties =
|
||||
new RedisProperties("pepboys", this.initTemplate(jcf, new StringRedisTemplate()));
|
||||
|
||||
@@ -508,7 +508,7 @@ public class RedisStoreOutboundChannelAdapterIntegrationTests extends RedisAvail
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testPropertiesSimple(){
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
StringRedisTemplate redisTemplate = new StringRedisTemplate();
|
||||
RedisProperties redisProperties =
|
||||
new RedisProperties("foo", this.initTemplate(jcf, redisTemplate));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-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.
|
||||
@@ -30,7 +30,6 @@ import java.util.Set;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.data.redis.core.ZSetOperations.TypedTuple;
|
||||
@@ -58,7 +57,7 @@ public class RedisStoreWritingMessageHandlerTests extends RedisAvailableTests{
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testListWithListPayloadParsedAndProvidedKey() {
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
String key = "foo";
|
||||
RedisList<String> redisList =
|
||||
new DefaultRedisList<String>(key, this.initTemplate(jcf, new StringRedisTemplate()));
|
||||
@@ -86,7 +85,7 @@ public class RedisStoreWritingMessageHandlerTests extends RedisAvailableTests{
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testListWithListPayloadParsedAndProvidedKeyAsHeader() {
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
String key = "foo";
|
||||
RedisList<String> redisList =
|
||||
new DefaultRedisList<String>(key, this.initTemplate(jcf, new StringRedisTemplate()));
|
||||
@@ -114,7 +113,7 @@ public class RedisStoreWritingMessageHandlerTests extends RedisAvailableTests{
|
||||
@RedisAvailable
|
||||
@Test(expected=MessageHandlingException.class)
|
||||
public void testListWithListPayloadParsedAndNoKey() {
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
String key = "foo";
|
||||
RedisList<String> redisList =
|
||||
new DefaultRedisList<String>(key, this.initTemplate(jcf, new RedisTemplate<String, String>()));
|
||||
@@ -136,7 +135,7 @@ public class RedisStoreWritingMessageHandlerTests extends RedisAvailableTests{
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testListWithListPayloadAsSingleEntry() {
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
String key = "foo";
|
||||
RedisList<List<String>> redisList =
|
||||
new DefaultRedisList<List<String>>(key, this.initTemplate(jcf, new RedisTemplate<String, List<String>>()));
|
||||
@@ -167,7 +166,7 @@ public class RedisStoreWritingMessageHandlerTests extends RedisAvailableTests{
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testZsetWithListPayloadParsedAndProvidedKeyDefault() {
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
String key = "foo";
|
||||
RedisZSet<String> redisZset =
|
||||
new DefaultRedisZSet<String>(key, this.initTemplate(jcf, new StringRedisTemplate()));
|
||||
@@ -205,7 +204,7 @@ public class RedisStoreWritingMessageHandlerTests extends RedisAvailableTests{
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testZsetWithListPayloadParsedAndProvidedKeyScoreIncrement() {
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
String key = "foo";
|
||||
RedisZSet<String> redisZset =
|
||||
new DefaultRedisZSet<String>(key, this.initTemplate(jcf, new StringRedisTemplate()));
|
||||
@@ -246,7 +245,7 @@ public class RedisStoreWritingMessageHandlerTests extends RedisAvailableTests{
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testZsetWithListPayloadParsedAndProvidedKeyScoreIncrementAsStringHeader() {// see INT-2775
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
String key = "foo";
|
||||
RedisZSet<String> redisZset =
|
||||
new DefaultRedisZSet<String>(key, this.initTemplate(jcf, new StringRedisTemplate()));
|
||||
@@ -287,7 +286,7 @@ public class RedisStoreWritingMessageHandlerTests extends RedisAvailableTests{
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testZsetWithListPayloadAsSingleEntryAndHeaderKeyHeaderScore() {
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
String key = "foo";
|
||||
RedisZSet<List<String>> redisZset =
|
||||
new DefaultRedisZSet<List<String>>(key, this.initTemplate(jcf, new RedisTemplate<String, List<String>>()));
|
||||
@@ -320,7 +319,7 @@ public class RedisStoreWritingMessageHandlerTests extends RedisAvailableTests{
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testZsetWithMapPayloadParsedHeaderKey() {
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
String key = "presidents";
|
||||
RedisZSet<String> redisZset =
|
||||
new DefaultRedisZSet<String>(key, this.initTemplate(jcf, new StringRedisTemplate()));
|
||||
@@ -362,7 +361,7 @@ public class RedisStoreWritingMessageHandlerTests extends RedisAvailableTests{
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testZsetWithMapPayloadPojoParsedHeaderKey() {
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
String key = "presidents";
|
||||
RedisZSet<President> redisZset =
|
||||
new DefaultRedisZSet<President>(key, this.initTemplate(jcf, new RedisTemplate<String, President>()));
|
||||
@@ -405,7 +404,7 @@ public class RedisStoreWritingMessageHandlerTests extends RedisAvailableTests{
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testZsetWithMapPayloadPojoAsSingleEntryHeaderKey() {
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
String key = "presidents";
|
||||
RedisZSet<Map<President, Double>> redisZset =
|
||||
new DefaultRedisZSet<Map<President, Double>>(key, this.initTemplate(jcf, new RedisTemplate<String, Map<President, Double>>()));
|
||||
@@ -435,7 +434,7 @@ public class RedisStoreWritingMessageHandlerTests extends RedisAvailableTests{
|
||||
@Test(expected=IllegalStateException.class)
|
||||
@RedisAvailable
|
||||
public void testListWithMapKeyExpression() {
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
String key = "foo";
|
||||
RedisStoreWritingMessageHandler handler =
|
||||
new RedisStoreWritingMessageHandler(jcf);
|
||||
@@ -447,7 +446,7 @@ public class RedisStoreWritingMessageHandlerTests extends RedisAvailableTests{
|
||||
@Test(expected=IllegalStateException.class)
|
||||
@RedisAvailable
|
||||
public void testSetWithMapKeyExpression() {
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
String key = "foo";
|
||||
RedisStoreWritingMessageHandler handler =
|
||||
new RedisStoreWritingMessageHandler(jcf);
|
||||
@@ -460,7 +459,7 @@ public class RedisStoreWritingMessageHandlerTests extends RedisAvailableTests{
|
||||
@Test(expected=IllegalStateException.class)
|
||||
@RedisAvailable
|
||||
public void testZsetWithMapKeyExpression() {
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
String key = "foo";
|
||||
RedisStoreWritingMessageHandler handler =
|
||||
new RedisStoreWritingMessageHandler(jcf);
|
||||
@@ -473,7 +472,7 @@ public class RedisStoreWritingMessageHandlerTests extends RedisAvailableTests{
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testMapWithMapKeyExpression() {
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
String key = "foo";
|
||||
RedisStoreWritingMessageHandler handler =
|
||||
new RedisStoreWritingMessageHandler(jcf);
|
||||
@@ -491,7 +490,7 @@ public class RedisStoreWritingMessageHandlerTests extends RedisAvailableTests{
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testPropertiesWithMapKeyExpression() {
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
String key = "foo";
|
||||
RedisStoreWritingMessageHandler handler =
|
||||
new RedisStoreWritingMessageHandler(jcf);
|
||||
|
||||
@@ -61,8 +61,8 @@
|
||||
map-key-expression="headers['baz']"
|
||||
collection-type="PROPERTIES"/>
|
||||
|
||||
<bean id="redisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
|
||||
<property name="port" value="7379"/>
|
||||
<bean id="redisConnectionFactory" class="org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory">
|
||||
<property name="port" value="#{T(org.springframework.integration.redis.rules.RedisAvailableRule).REDIS_PORT}"/>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-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.
|
||||
@@ -15,49 +15,71 @@
|
||||
*/
|
||||
package org.springframework.integration.redis.rules;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.junit.Assume;
|
||||
import org.junit.rules.MethodRule;
|
||||
import org.junit.runners.model.FrameworkMethod;
|
||||
import org.junit.runners.model.Statement;
|
||||
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
|
||||
|
||||
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
|
||||
|
||||
/**
|
||||
* @author Oleg Zhurakousky
|
||||
* @author Gunnar Hillert
|
||||
*
|
||||
* @author Artem Bilan
|
||||
*/
|
||||
public final class RedisAvailableRule implements MethodRule{
|
||||
public final class RedisAvailableRule implements MethodRule {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(RedisAvailableRule.class);
|
||||
public static final int REDIS_PORT = 6379;
|
||||
|
||||
public static final int REDIS_PORT = 7379;
|
||||
static ThreadLocal<LettuceConnectionFactory> connectionFactoryResource = new ThreadLocal<LettuceConnectionFactory>();
|
||||
|
||||
public Statement apply(final Statement base, final FrameworkMethod method, Object target) {
|
||||
return new Statement(){
|
||||
RedisAvailable redisAvailable = method.getAnnotation(RedisAvailable.class);
|
||||
if (redisAvailable != null) {
|
||||
LettuceConnectionFactory connectionFactory = null;
|
||||
try {
|
||||
connectionFactory = new LettuceConnectionFactory();
|
||||
connectionFactory.setPort(REDIS_PORT);
|
||||
connectionFactory.afterPropertiesSet();
|
||||
connectionFactory.getConnection();
|
||||
connectionFactoryResource.set(connectionFactory);
|
||||
}
|
||||
catch (Exception e) {
|
||||
if (connectionFactory != null) {
|
||||
connectionFactory.destroy();
|
||||
}
|
||||
return new Statement() {
|
||||
@Override
|
||||
public void evaluate() throws Throwable {
|
||||
Assume.assumeTrue("Skipping test due to Redis not being available on port: " + REDIS_PORT, false);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void evaluate() throws Throwable {
|
||||
RedisAvailable redisAvailable = method.getAnnotation(RedisAvailable.class);
|
||||
if (redisAvailable != null){
|
||||
return new Statement() {
|
||||
@Override
|
||||
public void evaluate() throws Throwable {
|
||||
try {
|
||||
|
||||
JedisConnectionFactory connectionFactory = new JedisConnectionFactory();
|
||||
connectionFactory.setPort(REDIS_PORT);
|
||||
connectionFactory.afterPropertiesSet();
|
||||
connectionFactory.getConnection();
|
||||
} catch (Exception e) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn(String.format("Redis is not available on " +
|
||||
"port '%s'. Skipping the test.", REDIS_PORT));
|
||||
base.evaluate();
|
||||
}
|
||||
finally {
|
||||
LettuceConnectionFactory connectionFactory = connectionFactoryResource.get();
|
||||
connectionFactoryResource.remove();
|
||||
if (connectionFactory != null) {
|
||||
connectionFactory.destroy();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return new Statement() {
|
||||
@Override
|
||||
public void evaluate() throws Throwable {
|
||||
base.evaluate();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,8 @@ import org.junit.Rule;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.data.redis.connection.RedisConnection;
|
||||
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
|
||||
import org.springframework.data.redis.core.BoundListOperations;
|
||||
import org.springframework.data.redis.core.BoundZSetOperations;
|
||||
import org.springframework.data.redis.core.RedisCallback;
|
||||
@@ -31,21 +32,20 @@ import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
/**
|
||||
* @author Oleg Zhurakousky
|
||||
* @author Gary Russell
|
||||
* @author Artem Bilan
|
||||
*
|
||||
*/
|
||||
public class RedisAvailableTests {
|
||||
|
||||
@Rule
|
||||
public RedisAvailableRule redisAvailableRule = new RedisAvailableRule();
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public JedisConnectionFactory getConnectionFactoryForTest(){
|
||||
JedisConnectionFactory jcf = new JedisConnectionFactory();
|
||||
jcf.setPort(7379);
|
||||
jcf.afterPropertiesSet();
|
||||
RedisTemplate rt = new RedisTemplate<UUID, Object>();
|
||||
rt.setConnectionFactory(jcf);
|
||||
public RedisConnectionFactory getConnectionFactoryForTest(){
|
||||
LettuceConnectionFactory connectionFactory = RedisAvailableRule.connectionFactoryResource.get();
|
||||
RedisTemplate<UUID, Object> rt = new RedisTemplate<UUID, Object>();
|
||||
rt.setConnectionFactory(connectionFactory);
|
||||
rt.afterPropertiesSet();
|
||||
rt.execute(new RedisCallback() {
|
||||
rt.execute(new RedisCallback<Object>() {
|
||||
|
||||
public Object doInRedis(RedisConnection connection)
|
||||
throws DataAccessException {
|
||||
@@ -53,13 +53,13 @@ public class RedisAvailableTests {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
return jcf;
|
||||
return connectionFactory;
|
||||
}
|
||||
|
||||
protected void prepareList(JedisConnectionFactory jcf){
|
||||
protected void prepareList(RedisConnectionFactory connectionFactory){
|
||||
|
||||
StringRedisTemplate redisTemplate = new StringRedisTemplate();
|
||||
redisTemplate.setConnectionFactory(jcf);
|
||||
redisTemplate.setConnectionFactory(connectionFactory);
|
||||
redisTemplate.afterPropertiesSet();
|
||||
BoundListOperations<String, String> ops = redisTemplate.boundListOps("presidents");
|
||||
|
||||
@@ -80,10 +80,10 @@ public class RedisAvailableTests {
|
||||
ops.rightPush("George Washington");
|
||||
}
|
||||
|
||||
protected void prepareZset(JedisConnectionFactory jcf){
|
||||
protected void prepareZset(RedisConnectionFactory connectionFactory){
|
||||
|
||||
StringRedisTemplate redisTemplate = new StringRedisTemplate();
|
||||
redisTemplate.setConnectionFactory(jcf);
|
||||
redisTemplate.setConnectionFactory(connectionFactory);
|
||||
redisTemplate.afterPropertiesSet();
|
||||
|
||||
BoundZSetOperations<String, String> ops = redisTemplate.boundZSetOps("presidents");
|
||||
|
||||
@@ -5,12 +5,8 @@
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd">
|
||||
|
||||
<beans:bean id="redisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
|
||||
<beans:property name="port" value="7379" />
|
||||
</beans:bean>
|
||||
|
||||
<beans:bean id="messageStore" class="org.springframework.integration.redis.store.RedisMessageStore">
|
||||
<beans:constructor-arg ref="redisConnectionFactory"/>
|
||||
<beans:constructor-arg value="#{T(org.springframework.integration.redis.store.DelayerHandlerRescheduleIntegrationTests).connectionFactory}"/>
|
||||
</beans:bean>
|
||||
|
||||
<channel id="output">
|
||||
|
||||
@@ -21,14 +21,17 @@ import static org.junit.Assert.fail;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.context.support.AbstractApplicationContext;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
|
||||
import org.springframework.integration.context.IntegrationContextUtils;
|
||||
import org.springframework.integration.handler.DelayHandler;
|
||||
import org.springframework.integration.redis.rules.RedisAvailable;
|
||||
import org.springframework.integration.redis.rules.RedisAvailableRule;
|
||||
import org.springframework.integration.redis.rules.RedisAvailableTests;
|
||||
import org.springframework.integration.store.MessageGroup;
|
||||
import org.springframework.integration.store.MessageGroupStore;
|
||||
@@ -47,9 +50,22 @@ public class DelayerHandlerRescheduleIntegrationTests extends RedisAvailableTest
|
||||
|
||||
public static final String DELAYER_ID = "delayerWithRedisMS";
|
||||
|
||||
public static LettuceConnectionFactory connectionFactory;
|
||||
|
||||
@Rule
|
||||
public LongRunningIntegrationTest longTests = new LongRunningIntegrationTest();
|
||||
|
||||
@BeforeClass
|
||||
public static void setup() {
|
||||
connectionFactory = new LettuceConnectionFactory();
|
||||
connectionFactory.setPort(RedisAvailableRule.REDIS_PORT);
|
||||
connectionFactory.afterPropertiesSet();
|
||||
}
|
||||
|
||||
public static void tearDown() {
|
||||
connectionFactory.destroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testDelayerHandlerRescheduleWithRedisMessageStore() throws Exception {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2007-2012 the original author or authors
|
||||
* Copyright 2007-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.
|
||||
@@ -35,9 +35,7 @@ import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.integration.channel.DirectChannel;
|
||||
import org.springframework.integration.channel.QueueChannel;
|
||||
import org.springframework.integration.history.MessageHistory;
|
||||
@@ -47,6 +45,8 @@ import org.springframework.integration.redis.rules.RedisAvailableTests;
|
||||
import org.springframework.integration.store.MessageGroup;
|
||||
import org.springframework.integration.store.SimpleMessageGroup;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
|
||||
/**
|
||||
* @author Oleg Zhurakousky
|
||||
@@ -57,7 +57,7 @@ public class RedisMessageGroupStoreTests extends RedisAvailableTests {
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testNonExistingEmptyMessageGroup() throws Exception{
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisMessageStore store = new RedisMessageStore(jcf);
|
||||
|
||||
MessageGroup messageGroup = store.getMessageGroup(1);
|
||||
@@ -69,7 +69,7 @@ public class RedisMessageGroupStoreTests extends RedisAvailableTests {
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testMessageGroupUpdatedDateChangesWithEachAddedMessage() throws Exception{
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisMessageStore store = new RedisMessageStore(jcf);
|
||||
|
||||
MessageGroup messageGroup = store.getMessageGroup(1);
|
||||
@@ -96,7 +96,7 @@ public class RedisMessageGroupStoreTests extends RedisAvailableTests {
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testMessageGroupWithAddedMessage() throws Exception{
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisMessageStore store = new RedisMessageStore(jcf);
|
||||
|
||||
MessageGroup messageGroup = store.getMessageGroup(1);
|
||||
@@ -114,7 +114,7 @@ public class RedisMessageGroupStoreTests extends RedisAvailableTests {
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testRemoveMessageGroup() throws Exception{
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisMessageStore store = new RedisMessageStore(jcf);
|
||||
|
||||
MessageGroup messageGroup = store.getMessageGroup(1);
|
||||
@@ -141,7 +141,7 @@ public class RedisMessageGroupStoreTests extends RedisAvailableTests {
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testCompleteMessageGroup() throws Exception{
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisMessageStore store = new RedisMessageStore(jcf);
|
||||
|
||||
MessageGroup messageGroup = store.getMessageGroup(1);
|
||||
@@ -155,7 +155,7 @@ public class RedisMessageGroupStoreTests extends RedisAvailableTests {
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testLastReleasedSequenceNumber() throws Exception{
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisMessageStore store = new RedisMessageStore(jcf);
|
||||
|
||||
MessageGroup messageGroup = store.getMessageGroup(1);
|
||||
@@ -169,7 +169,7 @@ public class RedisMessageGroupStoreTests extends RedisAvailableTests {
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testRemoveMessageFromTheGroup() throws Exception{
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisMessageStore store = new RedisMessageStore(jcf);
|
||||
|
||||
MessageGroup messageGroup = store.getMessageGroup(1);
|
||||
@@ -192,7 +192,7 @@ public class RedisMessageGroupStoreTests extends RedisAvailableTests {
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testWithMessageHistory() throws Exception{
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisMessageStore store = new RedisMessageStore(jcf);
|
||||
|
||||
store.getMessageGroup(1);
|
||||
@@ -219,7 +219,7 @@ public class RedisMessageGroupStoreTests extends RedisAvailableTests {
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testRemoveNonExistingMessageFromTheGroup() throws Exception{
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisMessageStore store = new RedisMessageStore(jcf);
|
||||
|
||||
MessageGroup messageGroup = store.getMessageGroup(1);
|
||||
@@ -230,7 +230,7 @@ public class RedisMessageGroupStoreTests extends RedisAvailableTests {
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testRemoveNonExistingMessageFromNonExistingTheGroup() throws Exception{
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisMessageStore store = new RedisMessageStore(jcf);
|
||||
store.removeMessageFromGroup(1, new GenericMessage<String>("2"));
|
||||
}
|
||||
@@ -240,7 +240,7 @@ public class RedisMessageGroupStoreTests extends RedisAvailableTests {
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testMultipleInstancesOfGroupStore() throws Exception{
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisMessageStore store1 = new RedisMessageStore(jcf);
|
||||
|
||||
RedisMessageStore store2 = new RedisMessageStore(jcf);
|
||||
@@ -261,7 +261,7 @@ public class RedisMessageGroupStoreTests extends RedisAvailableTests {
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testIteratorOfMessageGroups() throws Exception{
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisMessageStore store1 = new RedisMessageStore(jcf);
|
||||
RedisMessageStore store2 = new RedisMessageStore(jcf);
|
||||
|
||||
@@ -303,7 +303,7 @@ public class RedisMessageGroupStoreTests extends RedisAvailableTests {
|
||||
@Test
|
||||
@RedisAvailable @Ignore
|
||||
public void testConcurrentModifications() throws Exception{
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
final RedisMessageStore store1 = new RedisMessageStore(jcf);
|
||||
final RedisMessageStore store2 = new RedisMessageStore(jcf);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2007-2011 the original author or authors
|
||||
* Copyright 2007-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.
|
||||
@@ -15,24 +15,24 @@
|
||||
*/
|
||||
package org.springframework.integration.redis.store;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNotSame;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Properties;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.integration.channel.DirectChannel;
|
||||
import org.springframework.integration.history.MessageHistory;
|
||||
import org.springframework.integration.message.GenericMessage;
|
||||
import org.springframework.integration.redis.rules.RedisAvailable;
|
||||
import org.springframework.integration.redis.rules.RedisAvailableTests;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNotSame;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import org.springframework.messaging.Message;
|
||||
|
||||
/**
|
||||
* @author Oleg Zhurakousky
|
||||
@@ -42,62 +42,62 @@ public class RedisMessageStoreTests extends RedisAvailableTests {
|
||||
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testGetNonExistingMessage(){
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
public void testGetNonExistingMessage(){
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisMessageStore store = new RedisMessageStore(jcf);
|
||||
Message<?> message = store.getMessage(UUID.randomUUID());
|
||||
assertNull(message);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testGetMessageCountWhenEmpty(){
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
public void testGetMessageCountWhenEmpty(){
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisMessageStore store = new RedisMessageStore(jcf);
|
||||
assertEquals(0, store.getMessageCount());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testAddStringMessage(){
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
public void testAddStringMessage(){
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisMessageStore store = new RedisMessageStore(jcf);
|
||||
Message<String> stringMessage = new GenericMessage<String>("Hello Redis");
|
||||
Message<String> storedMessage = store.addMessage(stringMessage);
|
||||
assertNotSame(stringMessage, storedMessage);
|
||||
assertEquals("Hello Redis", storedMessage.getPayload());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testAddSerializableObjectMessage(){
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
public void testAddSerializableObjectMessage(){
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisMessageStore store = new RedisMessageStore(jcf);
|
||||
Address address = new Address();
|
||||
address.setAddress("1600 Pennsylvania Av, Washington, DC");
|
||||
Person person = new Person(address, "Barak Obama");
|
||||
|
||||
|
||||
Message<Person> objectMessage = new GenericMessage<Person>(person);
|
||||
Message<Person> storedMessage = store.addMessage(objectMessage);
|
||||
assertNotSame(objectMessage, storedMessage);
|
||||
assertEquals("Barak Obama", storedMessage.getPayload().getName());
|
||||
}
|
||||
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
@RedisAvailable
|
||||
public void testAddNonSerializableObjectMessage(){
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
public void testAddNonSerializableObjectMessage(){
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisMessageStore store = new RedisMessageStore(jcf);
|
||||
|
||||
|
||||
Message<Foo> objectMessage = new GenericMessage<Foo>(new Foo());
|
||||
store.addMessage(objectMessage);
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testAddAndGetStringMessage(){
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
public void testAddAndGetStringMessage(){
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisMessageStore store = new RedisMessageStore(jcf);
|
||||
Message<String> stringMessage = new GenericMessage<String>("Hello Redis");
|
||||
store.addMessage(stringMessage);
|
||||
@@ -108,8 +108,8 @@ public class RedisMessageStoreTests extends RedisAvailableTests {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testAddAndRemoveStringMessage(){
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
public void testAddAndRemoveStringMessage(){
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisMessageStore store = new RedisMessageStore(jcf);
|
||||
Message<String> stringMessage = new GenericMessage<String>("Hello Redis");
|
||||
store.addMessage(stringMessage);
|
||||
@@ -118,19 +118,19 @@ public class RedisMessageStoreTests extends RedisAvailableTests {
|
||||
assertEquals("Hello Redis", retrievedMessage.getPayload());
|
||||
assertNull(store.getMessage(stringMessage.getHeaders().getId()));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testWithMessageHistory() throws Exception{
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
public void testWithMessageHistory() throws Exception{
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisMessageStore store = new RedisMessageStore(jcf);
|
||||
|
||||
|
||||
Message<?> message = new GenericMessage<String>("Hello");
|
||||
DirectChannel fooChannel = new DirectChannel();
|
||||
fooChannel.setBeanName("fooChannel");
|
||||
DirectChannel barChannel = new DirectChannel();
|
||||
barChannel.setBeanName("barChannel");
|
||||
|
||||
|
||||
message = MessageHistory.write(message, fooChannel);
|
||||
message = MessageHistory.write(message, barChannel);
|
||||
store.addMessage(message);
|
||||
@@ -142,7 +142,7 @@ public class RedisMessageStoreTests extends RedisAvailableTests {
|
||||
assertEquals("fooChannel", fooChannelHistory.get("name"));
|
||||
assertEquals("channel", fooChannelHistory.get("type"));
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public static class Person implements Serializable{
|
||||
private Address address;
|
||||
@@ -176,8 +176,8 @@ public class RedisMessageStoreTests extends RedisAvailableTests {
|
||||
this.address = address;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class Foo{
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,8 @@ import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
|
||||
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.core.BoundValueOperations;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.integration.redis.rules.RedisAvailable;
|
||||
@@ -36,7 +37,7 @@ public class RedisMetadataStoreTests extends RedisAvailableTests {
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testGetNonExistingKeyValue(){
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisMetadataStore metadataStore = new RedisMetadataStore(jcf);
|
||||
String retrievedValue = metadataStore.get("does-not-exist");
|
||||
assertNull(retrievedValue);
|
||||
@@ -45,7 +46,7 @@ public class RedisMetadataStoreTests extends RedisAvailableTests {
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testPersistKeyValue(){
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisMetadataStore metadataStore = new RedisMetadataStore(jcf);
|
||||
metadataStore.put("RedisMetadataStoreTests-Spring", "Integration");
|
||||
|
||||
@@ -59,7 +60,7 @@ public class RedisMetadataStoreTests extends RedisAvailableTests {
|
||||
@RedisAvailable
|
||||
public void testGetValueFromMetadataStore(){
|
||||
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisMetadataStore metadataStore = new RedisMetadataStore(jcf);
|
||||
metadataStore.put("RedisMetadataStoreTests-GetValue", "Hello Redis");
|
||||
|
||||
@@ -71,7 +72,7 @@ public class RedisMetadataStoreTests extends RedisAvailableTests {
|
||||
@RedisAvailable
|
||||
public void testPersistEmptyStringToMetadataStore(){
|
||||
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisMetadataStore metadataStore = new RedisMetadataStore(jcf);
|
||||
metadataStore.put("RedisMetadataStoreTests-PersistEmpty", "");
|
||||
|
||||
@@ -83,7 +84,7 @@ public class RedisMetadataStoreTests extends RedisAvailableTests {
|
||||
@RedisAvailable
|
||||
public void testPersistNullStringToMetadataStore(){
|
||||
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisMetadataStore metadataStore = new RedisMetadataStore(jcf);
|
||||
|
||||
try {
|
||||
@@ -101,7 +102,7 @@ public class RedisMetadataStoreTests extends RedisAvailableTests {
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testPersistWithEmptyKeyToMetadataStore(){
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisMetadataStore metadataStore = new RedisMetadataStore(jcf);
|
||||
metadataStore.put("", "PersistWithEmptyKey");
|
||||
|
||||
@@ -112,7 +113,7 @@ public class RedisMetadataStoreTests extends RedisAvailableTests {
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testPersistWithNullKeyToMetadataStore(){
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisMetadataStore metadataStore = new RedisMetadataStore(jcf);
|
||||
|
||||
try {
|
||||
@@ -129,7 +130,7 @@ public class RedisMetadataStoreTests extends RedisAvailableTests {
|
||||
@Test
|
||||
@RedisAvailable
|
||||
public void testGetValueWithNullKeyFromMetadataStore(){
|
||||
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
|
||||
RedisMetadataStore metadataStore = new RedisMetadataStore(jcf);
|
||||
|
||||
try {
|
||||
|
||||
@@ -4,19 +4,19 @@
|
||||
xmlns:int="http://www.springframework.org/schema/integration"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd">
|
||||
|
||||
|
||||
<int:aggregator input-channel="inputChannel" output-channel="outputChannel" message-store="redisStore"/>
|
||||
|
||||
|
||||
<int:channel id="outputChannel">
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
|
||||
|
||||
<bean id="redisStore" class="org.springframework.integration.redis.store.RedisMessageStore">
|
||||
<constructor-arg ref="redisConnectionFactory"/>
|
||||
</bean>
|
||||
|
||||
<bean id="redisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
|
||||
<property name="port" value="7379" />
|
||||
|
||||
<bean id="redisConnectionFactory" class="org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory">
|
||||
<property name="port" value="#{T(org.springframework.integration.redis.rules.RedisAvailableRule).REDIS_PORT}"/>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-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.
|
||||
@@ -20,6 +20,7 @@ import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.DirectFieldAccessor;
|
||||
import org.springframework.integration.file.remote.AbstractFileInfo;
|
||||
import org.springframework.integration.file.remote.gateway.AbstractRemoteFileOutboundGateway;
|
||||
import org.springframework.integration.file.remote.session.SessionFactory;
|
||||
@@ -29,7 +30,7 @@ import com.jcraft.jsch.ChannelSftp.LsEntry;
|
||||
|
||||
/**
|
||||
* Outbound Gateway for performing remote file operations via SFTP.
|
||||
*
|
||||
*
|
||||
* @author Gary Russell
|
||||
* @since 2.1
|
||||
*/
|
||||
@@ -59,6 +60,11 @@ public class SftpOutboundGateway extends AbstractRemoteFileOutboundGateway<LsEnt
|
||||
return file.getFilename();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getFilename(AbstractFileInfo<LsEntry> file) {
|
||||
return file.getFilename();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<AbstractFileInfo<LsEntry>> asFileInfoList(Collection<LsEntry> files) {
|
||||
List<AbstractFileInfo<LsEntry>> canonicalFiles = new ArrayList<AbstractFileInfo<LsEntry>>();
|
||||
@@ -73,4 +79,11 @@ public class SftpOutboundGateway extends AbstractRemoteFileOutboundGateway<LsEnt
|
||||
return ((long)file.getAttrs().getMTime()) * 1000;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LsEntry enhanceNameWithSubDirectory(LsEntry file, String directory) {
|
||||
DirectFieldAccessor accessor = new DirectFieldAccessor(file);
|
||||
accessor.setPropertyValue("filename", directory + file.getFilename());
|
||||
return file;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -414,6 +414,23 @@
|
||||
Identifies directory path (e.g.,
|
||||
"/local/mytransfers") where file will be
|
||||
transferred TO.
|
||||
This attribute is mutually exclusive with 'local-directory-expression'.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="local-directory-expression" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Specifies SpEL expression to
|
||||
generate the directory path where file will be
|
||||
transferred TO, when using 'get' and 'mget' commands.
|
||||
The root object of the SpEL evaluation is the request Message,
|
||||
but the name of the source
|
||||
remote directory is also provided as the 'remoteDirectory' variable.
|
||||
For example, a valid expression might be:
|
||||
"'/local/' + #remoteDirectory.toUpperCase() + headers.foo".
|
||||
Only used with 'get' and 'mget' commands.
|
||||
This attribute is mutually exclusive with 'local-directory'.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
|
||||
@@ -17,16 +17,17 @@
|
||||
package org.springframework.integration.sftp.config;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.BeanDefinitionStoreException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
@@ -75,7 +76,6 @@ public class OutboundChannelAdapterParserTests {
|
||||
assertNotNull(TestUtils.getPropertyValue(handler, "temporaryDirectoryExpressionProcessor"));
|
||||
assertEquals(context.getBean("fileNameGenerator"), TestUtils.getPropertyValue(handler, "fileNameGenerator"));
|
||||
assertEquals("UTF-8", TestUtils.getPropertyValue(handler, "charset"));
|
||||
assertNotNull(TestUtils.getPropertyValue(handler, "temporaryDirectory"));
|
||||
CachingSessionFactory<?> sessionFactory = TestUtils.getPropertyValue(handler, "sessionFactory", CachingSessionFactory.class);
|
||||
DefaultSftpSessionFactory clientFactory = TestUtils.getPropertyValue(sessionFactory, "sessionFactory", DefaultSftpSessionFactory.class);
|
||||
assertEquals("localhost", TestUtils.getPropertyValue(clientFactory, "host"));
|
||||
@@ -108,7 +108,6 @@ public class OutboundChannelAdapterParserTests {
|
||||
String fileNameGeneratorExpression = (String) TestUtils.getPropertyValue(generator, "expression");
|
||||
assertEquals("payload.getName() + '-foo'", fileNameGeneratorExpression);
|
||||
assertEquals("UTF-8", TestUtils.getPropertyValue(handler, "charset"));
|
||||
assertNotNull(TestUtils.getPropertyValue(handler, "temporaryDirectory"));
|
||||
assertNull(TestUtils.getPropertyValue(handler, "temporaryDirectoryExpressionProcessor"));
|
||||
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ public class SftpOutboundGatewayParserTests {
|
||||
assertEquals("X", TestUtils.getPropertyValue(gateway, "remoteFileSeparator"));
|
||||
assertNotNull(TestUtils.getPropertyValue(gateway, "sessionFactory"));
|
||||
assertNotNull(TestUtils.getPropertyValue(gateway, "outputChannel"));
|
||||
assertEquals(new File("local-test-dir"), TestUtils.getPropertyValue(gateway, "localDirectory"));
|
||||
assertEquals("local-test-dir", TestUtils.getPropertyValue(gateway, "localDirectoryExpression.literalValue"));
|
||||
assertFalse((Boolean) TestUtils.getPropertyValue(gateway, "autoCreateLocalDirectory"));
|
||||
assertTrue(TestUtils.getPropertyValue(gateway, "requiresReply", Boolean.class));
|
||||
assertNotNull(TestUtils.getPropertyValue(gateway, "filter"));
|
||||
@@ -97,7 +97,7 @@ public class SftpOutboundGatewayParserTests {
|
||||
assertNotNull(TestUtils.getPropertyValue(gateway, "sessionFactory"));
|
||||
assertTrue(TestUtils.getPropertyValue(gateway, "sessionFactory") instanceof CachingSessionFactory);
|
||||
assertNotNull(TestUtils.getPropertyValue(gateway, "outputChannel"));
|
||||
assertEquals(new File("local-test-dir"), TestUtils.getPropertyValue(gateway, "localDirectory"));
|
||||
assertEquals("local-test-dir", TestUtils.getPropertyValue(gateway, "localDirectoryExpression.literalValue"));
|
||||
assertFalse((Boolean) TestUtils.getPropertyValue(gateway, "autoCreateLocalDirectory"));
|
||||
assertEquals(Command.GET, TestUtils.getPropertyValue(gateway, "command"));
|
||||
assertFalse(TestUtils.getPropertyValue(gateway, "requiresReply", Boolean.class));
|
||||
|
||||
@@ -108,8 +108,11 @@ public class SftpOutboundTests {
|
||||
handler.setBeanFactory(mock(BeanFactory.class));
|
||||
handler.afterPropertiesSet();
|
||||
|
||||
handler.handleMessage(new GenericMessage<String>("hello"));
|
||||
handler.handleMessage(new GenericMessage<String>("String data"));
|
||||
assertTrue(new File("remote-target-dir", "foo.txt").exists());
|
||||
byte[] inFile = FileCopyUtils.copyToByteArray(file);
|
||||
assertEquals("String data", new String(inFile));
|
||||
file.delete();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -128,8 +131,11 @@ public class SftpOutboundTests {
|
||||
handler.setBeanFactory(mock(BeanFactory.class));
|
||||
handler.afterPropertiesSet();
|
||||
|
||||
handler.handleMessage(new GenericMessage<byte[]>("hello".getBytes()));
|
||||
handler.handleMessage(new GenericMessage<byte[]>("byte[] data".getBytes()));
|
||||
assertTrue(new File("remote-target-dir", "foo.txt").exists());
|
||||
byte[] inFile = FileCopyUtils.copyToByteArray(file);
|
||||
assertEquals("byte[] data", new String(inFile));
|
||||
file.delete();
|
||||
}
|
||||
|
||||
@Test //INT-2275
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
<?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-sftp="http://www.springframework.org/schema/integration/sftp"
|
||||
xmlns:int="http://www.springframework.org/schema/integration"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/integration/sftp
|
||||
http://www.springframework.org/schema/integration/sftp/spring-integration-sftp.xsd
|
||||
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||
|
||||
<int:channel id="output">
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
|
||||
<int:channel id="inboundGet"/>
|
||||
|
||||
<int-sftp:outbound-gateway session-factory="ftpSessionFactory"
|
||||
request-channel="inboundGet"
|
||||
command="get"
|
||||
expression="payload"
|
||||
local-directory-expression="'/tmp/sftpOutboundTests/' + #remoteDirectory.toUpperCase()"
|
||||
local-filename-generator-expression="#remoteFileName.replaceFirst('ftpSource', 'localTarget')"
|
||||
reply-channel="output"/>
|
||||
|
||||
<int:channel id="invalidDirExpression"/>
|
||||
|
||||
<int-sftp:outbound-gateway session-factory="ftpSessionFactory"
|
||||
request-channel="invalidDirExpression"
|
||||
command="get"
|
||||
expression="payload"
|
||||
local-directory-expression="T(java.io.File).separator + #remoteDirectory + '?:'"
|
||||
reply-channel="output"/>
|
||||
|
||||
<int:channel id="inboundMGet"/>
|
||||
|
||||
<int-sftp:outbound-gateway session-factory="ftpSessionFactory"
|
||||
request-channel="inboundMGet"
|
||||
command="mget"
|
||||
expression="payload"
|
||||
local-directory-expression="'/tmp/sftpOutboundTests/' + #remoteDirectory"
|
||||
local-filename-generator-expression="#remoteFileName.replaceFirst('ftpSource', 'localTarget')"
|
||||
reply-channel="output"/>
|
||||
|
||||
<int:channel id="inboundMGetRecursive"/>
|
||||
|
||||
<int-sftp:outbound-gateway session-factory="ftpSessionFactory"
|
||||
request-channel="inboundMGetRecursive"
|
||||
command="mget"
|
||||
expression="payload"
|
||||
command-options="-R"
|
||||
local-directory-expression="'/tmp/sftpOutboundTests/' + #remoteDirectory"
|
||||
local-filename-generator-expression="#remoteFileName.replaceFirst('ftpSource', 'localTarget')"
|
||||
reply-channel="output"/>
|
||||
|
||||
<int:channel id="inboundMGetRecursiveFiltered"/>
|
||||
|
||||
<int-sftp:outbound-gateway session-factory="ftpSessionFactory"
|
||||
request-channel="inboundMGetRecursiveFiltered"
|
||||
command="mget"
|
||||
expression="payload"
|
||||
command-options="-R"
|
||||
filename-regex="(subSftpSource|.*1.txt)"
|
||||
local-directory-expression="'/tmp/sftpOutboundTests/' + #remoteDirectory"
|
||||
local-filename-generator-expression="#remoteFileName.replaceFirst('ftpSource', 'localTarget')"
|
||||
reply-channel="output"/>
|
||||
|
||||
<bean id="ftpSessionFactory" class="org.mockito.Mockito" factory-method="mock">
|
||||
<constructor-arg value="org.springframework.integration.file.remote.session.SessionFactory" />
|
||||
</bean>
|
||||
|
||||
<beans profile="realSSH">
|
||||
<bean id="ftpSessionFactory"
|
||||
class="org.springframework.integration.sftp.session.DefaultSftpSessionFactory">
|
||||
<property name="host" value="localhost"/>
|
||||
<property name="user" value="ftptest"/>
|
||||
<property name="password" value="ftptest"/>
|
||||
</bean>
|
||||
</beans>
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,255 @@
|
||||
/*
|
||||
* Copyright 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.integration.sftp.outbound;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.DirectFieldAccessor;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.channel.DirectChannel;
|
||||
import org.springframework.integration.core.PollableChannel;
|
||||
import org.springframework.integration.file.remote.session.Session;
|
||||
import org.springframework.integration.file.remote.session.SessionFactory;
|
||||
import org.springframework.integration.message.GenericMessage;
|
||||
import org.springframework.integration.sftp.session.SftpFileInfo;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import com.jcraft.jsch.ChannelSftp.LsEntry;
|
||||
import com.jcraft.jsch.SftpATTRS;
|
||||
|
||||
/**
|
||||
* Run with -Dspring-profiles-active=realSSH to run with a real SSH server.
|
||||
*
|
||||
* Assumes ftptest account on localhost with the following directory tree in the user's root...
|
||||
*
|
||||
* <pre class="code">
|
||||
* $ tree sftpSource/
|
||||
* sftpSource/
|
||||
* ├── sftpSource1.txt
|
||||
* ├── sftpSource2.txt
|
||||
* └── subSftpSource
|
||||
* └── subSftpSource1.txt
|
||||
* </pre>
|
||||
*
|
||||
* @author Artem Bilan
|
||||
* @author Gary Russell
|
||||
* @since 3.0
|
||||
*/
|
||||
@ContextConfiguration
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
public class SftpServerOutboundTests {
|
||||
|
||||
@Autowired
|
||||
private PollableChannel output;
|
||||
|
||||
@Autowired
|
||||
private DirectChannel inboundGet;
|
||||
|
||||
@Autowired
|
||||
private DirectChannel invalidDirExpression;
|
||||
|
||||
@Autowired
|
||||
private DirectChannel inboundMGet;
|
||||
|
||||
@Autowired
|
||||
private DirectChannel inboundMGetRecursive;
|
||||
|
||||
@Autowired
|
||||
private DirectChannel inboundMGetRecursiveFiltered;
|
||||
|
||||
@Autowired
|
||||
private SessionFactory<SftpFileInfo> sessionFactory;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
purge();
|
||||
setUpMocksIfNeeded();
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
private void setUpMocksIfNeeded() throws IOException {
|
||||
if (sessionFactory.toString().startsWith("Mock for")) {
|
||||
Session session = mock(Session.class);
|
||||
when(sessionFactory.getSession()).thenReturn(session);
|
||||
LsEntry entry1 = mock(LsEntry.class);
|
||||
SftpATTRS attrs1 = mock(SftpATTRS.class);
|
||||
when(entry1.getAttrs()).thenReturn(attrs1);
|
||||
when(entry1.getFilename()).thenReturn("sftpSource1.txt");
|
||||
LsEntry entry2 = mock(LsEntry.class);
|
||||
SftpATTRS attrs2 = mock(SftpATTRS.class);
|
||||
when(entry2.getAttrs()).thenReturn(attrs2);
|
||||
when(entry2.getFilename()).thenReturn("sftpSource2.txt");
|
||||
LsEntry entry3 = mock(LsEntry.class);
|
||||
when(entry3.getFilename()).thenReturn("subSftpSource");
|
||||
SftpATTRS attrs3 = mock(SftpATTRS.class);
|
||||
when(entry3.getAttrs()).thenReturn(attrs3);
|
||||
when(attrs3.isDir()).thenReturn(true);
|
||||
LsEntry entry4 = mock(LsEntry.class);
|
||||
SftpATTRS attrs4 = mock(SftpATTRS.class);
|
||||
when(entry4.getAttrs()).thenReturn(attrs4);
|
||||
// recursion uses a DFA to update the filename to include the subdirectory
|
||||
new DirectFieldAccessor(entry4).setPropertyValue("filename", "subSftpSource1.txt");
|
||||
when(entry4.getFilename()).thenCallRealMethod();
|
||||
when(session.list("sftpSource/sftpSource1.txt")).thenReturn(new LsEntry[] {
|
||||
entry1
|
||||
});
|
||||
when(session.list("sftpSource/")).thenReturn(new LsEntry[] {
|
||||
entry1, entry2, entry3
|
||||
});
|
||||
when(session.list("sftpSource/subSftpSource/")).thenReturn(new LsEntry[] {
|
||||
entry4
|
||||
});
|
||||
when(session.list("sftpSource/subSftpSource/subSftpSource1.txt")).thenReturn(new LsEntry[] {
|
||||
entry4
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@After
|
||||
public void purge() {
|
||||
File local = new File("/tmp/sftpOutboundTests/");
|
||||
purge(local);
|
||||
local.delete();
|
||||
}
|
||||
|
||||
private void purge(File local) {
|
||||
File[] files = local.listFiles();
|
||||
if (files != null) {
|
||||
for (File file : files) {
|
||||
if (file.isDirectory()) {
|
||||
this.purge(file);
|
||||
}
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInt2866LocalDirectoryExpressionGET() {
|
||||
String dir = "sftpSource/";
|
||||
this.inboundGet.send(new GenericMessage<Object>(dir + "sftpSource1.txt"));
|
||||
Message<?> result = this.output.receive(1000);
|
||||
assertNotNull(result);
|
||||
File localFile = (File) result.getPayload();
|
||||
assertThat(localFile.getPath().replaceAll(java.util.regex.Matcher.quoteReplacement(File.separator), "/"),
|
||||
Matchers.containsString(dir.toUpperCase()));
|
||||
|
||||
dir = "sftpSource/subSftpSource/";
|
||||
this.inboundGet.send(new GenericMessage<Object>(dir + "subSftpSource1.txt"));
|
||||
result = this.output.receive(1000);
|
||||
assertNotNull(result);
|
||||
localFile = (File) result.getPayload();
|
||||
assertThat(localFile.getPath().replaceAll(java.util.regex.Matcher.quoteReplacement(File.separator), "/"),
|
||||
Matchers.containsString(dir.toUpperCase()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInt2866InvalidLocalDirectoryExpression() {
|
||||
try {
|
||||
this.invalidDirExpression.send(new GenericMessage<Object>("sftpSource/sftpSource1.txt"));
|
||||
fail("Exception expected.");
|
||||
}
|
||||
catch (Exception e) {
|
||||
Throwable cause = e.getCause();
|
||||
assertThat(cause, Matchers.instanceOf(IllegalArgumentException.class));
|
||||
assertThat(cause.getMessage(), Matchers.startsWith("Failed to make local directory"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testInt2866LocalDirectoryExpressionMGET() {
|
||||
String dir = "sftpSource/";
|
||||
this.inboundMGet.send(new GenericMessage<Object>(dir + "*.txt"));
|
||||
Message<?> result = this.output.receive(1000);
|
||||
assertNotNull(result);
|
||||
List<File> localFiles = (List<File>) result.getPayload();
|
||||
|
||||
for (File file : localFiles) {
|
||||
assertThat(file.getPath().replaceAll(java.util.regex.Matcher.quoteReplacement(File.separator), "/"),
|
||||
Matchers.containsString(dir));
|
||||
}
|
||||
|
||||
dir = "sftpSource/subSftpSource/";
|
||||
this.inboundMGet.send(new GenericMessage<Object>(dir + "*.txt"));
|
||||
result = this.output.receive(1000);
|
||||
assertNotNull(result);
|
||||
localFiles = (List<File>) result.getPayload();
|
||||
|
||||
for (File file : localFiles) {
|
||||
assertThat(file.getPath().replaceAll(java.util.regex.Matcher.quoteReplacement(File.separator), "/"),
|
||||
Matchers.containsString(dir));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testInt3172LocalDirectoryExpressionMGETRecursive() {
|
||||
String dir = "sftpSource/";
|
||||
this.inboundMGetRecursive.send(new GenericMessage<Object>(dir + "*"));
|
||||
Message<?> result = this.output.receive(1000);
|
||||
assertNotNull(result);
|
||||
List<File> localFiles = (List<File>) result.getPayload();
|
||||
assertEquals(3, localFiles.size());
|
||||
|
||||
for (File file : localFiles) {
|
||||
assertThat(file.getPath().replaceAll(java.util.regex.Matcher.quoteReplacement(File.separator), "/"),
|
||||
Matchers.containsString(dir));
|
||||
}
|
||||
assertThat(localFiles.get(2).getPath().replaceAll(java.util.regex.Matcher.quoteReplacement(File.separator), "/"),
|
||||
Matchers.containsString(dir + "subSftpSource"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testInt3172LocalDirectoryExpressionMGETRecursiveFiltered() {
|
||||
String dir = "sftpSource/";
|
||||
this.inboundMGetRecursiveFiltered.send(new GenericMessage<Object>(dir + "*"));
|
||||
Message<?> result = this.output.receive(1000);
|
||||
assertNotNull(result);
|
||||
List<File> localFiles = (List<File>) result.getPayload();
|
||||
// should have filtered sftpSource2.txt
|
||||
assertEquals(2, localFiles.size());
|
||||
|
||||
for (File file : localFiles) {
|
||||
assertThat(file.getPath().replaceAll(java.util.regex.Matcher.quoteReplacement(File.separator), "/"),
|
||||
Matchers.containsString(dir));
|
||||
}
|
||||
assertThat(localFiles.get(1).getPath().replaceAll(java.util.regex.Matcher.quoteReplacement(File.separator), "/"),
|
||||
Matchers.containsString(dir + "subSftpSource"));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -25,9 +25,10 @@
|
||||
<constructor-arg name="connectionFactory" ref="redisConnectionFactory"/>
|
||||
</bean>
|
||||
|
||||
<bean id="redisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
|
||||
<bean id="redisConnectionFactory" class="org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory">
|
||||
<property name="port" value="#{T(org.springframework.integration.redis.rules.RedisAvailableRule).REDIS_PORT}"/>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
|
||||
|
||||
|
||||
@@ -351,6 +351,7 @@ protected void postProcessClientBeforeConnect(T client) throws IOException {
|
||||
<listitem>-f - do not sort the list</listitem>
|
||||
<listitem>-dirs - include directories (excluded by default)</listitem>
|
||||
<listitem>-links - include symbolic links (excluded by default)</listitem>
|
||||
<listitem>-R - list the remote directory recursively</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
<para>
|
||||
@@ -366,6 +367,13 @@ protected void postProcessClientBeforeConnect(T client) throws IOException {
|
||||
The remote directory that the <emphasis>ls</emphasis> command acted on is provided
|
||||
in the <classname>file_remoteDirectory</classname> header.
|
||||
</para>
|
||||
<para>
|
||||
When using the recursive option (<code>-R</code>), the <code>fileName</code> includes any subdirectory
|
||||
elements, representing a relative path to the file (relative to the remote directory). If the <code>-dirs</code>
|
||||
option is included, each recursive directory is also returned as an element in the list. In this case,
|
||||
it is recommended that the <code>-1</code> is not used because you would not be able to determine files Vs.
|
||||
directories, which is achievable using the <code>FileInfo</code> objects.
|
||||
</para>
|
||||
<para><emphasis role="bold">get</emphasis></para>
|
||||
<para>
|
||||
<emphasis>get</emphasis> retrieves a remote file and supports the following option:
|
||||
@@ -399,6 +407,27 @@ protected void postProcessClientBeforeConnect(T client) throws IOException {
|
||||
for the filenames is
|
||||
provided in the <classname>file_remoteFile</classname> header.
|
||||
</para>
|
||||
<note>
|
||||
<title>Notes for when using recursion (<code>-R</code>)</title>
|
||||
<para>
|
||||
The pattern is ignored, and <code>*</code> is assumed. By
|
||||
default, the entire remote tree is retrieved. However, files in the tree can be filtered, by providing a
|
||||
<classname>FileListFilter</classname>; directories in the tree can also be filtered this way.
|
||||
A <classname>FileListFilter</classname> can be provided by reference or by <code>filename-pattern</code>
|
||||
or <code>filename-regex</code> attributes. For example,
|
||||
<code>filename-regex="(subDir|.*1.txt)"</code> will retrieve all files ending with <code>1.txt</code> in the
|
||||
remote directory and the subdirectory <code>subDir</code>. If a subdirectory is filtered, no additional
|
||||
traversal of that subdirectory is performed.
|
||||
</para>
|
||||
<para>
|
||||
The <code>-dirs</code> option is not allowed (the recursive mget uses the recursive <code>ls</code> to
|
||||
obtain the directory tree and the directories themselves cannot be included in the list).
|
||||
</para>
|
||||
<para>
|
||||
Typically, you would use the <code>#remoteDirectory</code> variable in the <code>local-directory-expression</code>
|
||||
so that the remote directory structure is retained locally.
|
||||
</para>
|
||||
</note>
|
||||
<para><emphasis role="bold">rm</emphasis></para>
|
||||
<para>
|
||||
The <emphasis>rm</emphasis> command has no options.
|
||||
@@ -433,7 +462,16 @@ protected void postProcessClientBeforeConnect(T client) throws IOException {
|
||||
defines a SpEL expression to generate the name of local file(s) during the transfer.
|
||||
The root object of the evaluation context is the request Message but, in addition, the <code>remoteFileName</code>
|
||||
variable is also available, which is particularly useful for <emphasis>mget</emphasis>, for
|
||||
example: <code>local-filename-generator-expression="#remoteFileName.toUpperCase() + headers.foo"</code>
|
||||
example: <code>local-filename-generator-expression="#remoteFileName.toUpperCase() + headers.foo"</code>.
|
||||
</para>
|
||||
<para>
|
||||
The <emphasis>get</emphasis> and <emphasis>mget</emphasis> commands support
|
||||
the <emphasis>local-directory-expression</emphasis> attribute. It
|
||||
defines a SpEL expression to generate the name of local directory(ies) during the transfer.
|
||||
The root object of the evaluation context is the request Message but, in addition, the <code>remoteDirectory</code>
|
||||
variable is also available, which is particularly useful for <emphasis>mget</emphasis>, for
|
||||
example: <code>local-directory-expression="'/tmp/local/' + #remoteDirectory.toUpperCase() + headers.foo"</code>.
|
||||
This attribute is mutually exclusive with <emphasis>local-directory</emphasis> attribute.
|
||||
</para>
|
||||
<para>
|
||||
For all commands, the PATH that the command acts on is provided by the 'expression'
|
||||
|
||||
@@ -116,9 +116,10 @@ public interface Cafe {
|
||||
|
||||
<programlisting language="xml"><![CDATA[<int:gateway id="myGateway" service-interface="org.foo.bar.TestGateway"
|
||||
default-request-channel="inputC">
|
||||
<int:default-header name="calledMethod" expression="#gatewayMethod.name"/>
|
||||
<int:method name="echo" request-channel="inputA" reply-timeout="2" request-timeout="200"/>
|
||||
<int:method name="echoUpperCase" request-channel="inputB"/>
|
||||
<int:method name="echoViaDefault"/>
|
||||
<int:method name="echoUpperCase" request-channel="inputB"/>
|
||||
<int:method name="echoViaDefault"/>
|
||||
</int:gateway>]]></programlisting>
|
||||
|
||||
<para>
|
||||
@@ -145,6 +146,45 @@ public interface Cafe {
|
||||
In the above case you can clearly see how a different value will be set for the 'RESPONSE_TYPE'
|
||||
header based on the gateway's method.
|
||||
</para>
|
||||
<para><emphasis role="bold">Expressions and "Global" Headers</emphasis></para>
|
||||
<para>
|
||||
The <code><header/></code> element supports <code>expression</code> as an alternative to
|
||||
<code>value</code>. The SpEL expression is evaluated to determine the value of the header. There is no
|
||||
<code>#root</code> object but the following variables are available:
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
#args - an <code>Object[]</code> containing the method arguments
|
||||
</listitem>
|
||||
<listitem>
|
||||
#gatewayMethod - the <classname>java.reflect.Method</classname> object representing the method in the
|
||||
<code>service-interface</code> that was invoked. A header containing this variable can be used
|
||||
later in the flow, for example, for routing. For example, if you wish to route on the simple method
|
||||
name, you might add a header, with expression <code>#gatewayMethod.name</code>.
|
||||
<note>
|
||||
The <classname>java.reflect.Method</classname> is not serializable; a header with expression
|
||||
<code>#gatewayMethod</code> will be lost if you later serialize the message. So, you may wish
|
||||
to use <code>#gatewayMethod.name</code> or <code>#gatewayMethod.toString()</code> in those cases;
|
||||
the <code>toString()</code> method provides a String representation of the method, including
|
||||
parameter and return types.
|
||||
</note>
|
||||
<note>
|
||||
Prior to 3.0, the <code>#method</code> variable was available, representing the method name only.
|
||||
This is still available, but deprecated; use <code>#gatewayMethod.name</code> instead.
|
||||
</note>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
<para>
|
||||
Since 3.0, <code><default-header/></code>s can be defined to add headers to all messages produced
|
||||
by the gateway, regardless of the method invoked. Specific headers defined for a method take precedence
|
||||
over default headers. Specific headers defined for a method here will override any <code>@Header</code> annotations
|
||||
in the service interface. However, default headers will NOT override any <code>@Header</code> annotations
|
||||
in the service interface.
|
||||
</para>
|
||||
<para>
|
||||
The gateway now also supports a <code>default-payload-expression</code> which will be applied for all methods
|
||||
(unless overridden).
|
||||
</para>
|
||||
|
||||
</section>
|
||||
<section id="gateway-calling-no-argument-methods">
|
||||
|
||||
@@ -387,6 +387,7 @@ xsi:schemaLocation="http://www.springframework.org/schema/integration/sftp
|
||||
<listitem>-f - do not sort the list</listitem>
|
||||
<listitem>-dirs - include directories (excluded by default)</listitem>
|
||||
<listitem>-links - include symbolic links (excluded by default)</listitem>
|
||||
<listitem>-R - list the remote directory recursively</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
<para>
|
||||
@@ -402,6 +403,13 @@ xsi:schemaLocation="http://www.springframework.org/schema/integration/sftp
|
||||
The remote directory that the <emphasis>ls</emphasis> command acted on is provided
|
||||
in the <classname>file_remoteDirectory</classname> header.
|
||||
</para>
|
||||
<para>
|
||||
When using the recursive option (<code>-R</code>), the <code>fileName</code> includes any subdirectory
|
||||
elements, representing a relative path to the file (relative to the remote directory). If the <code>-dirs</code>
|
||||
option is included, each recursive directory is also returned as an element in the list. In this case,
|
||||
it is recommended that the <code>-1</code> is not used because you would not be able to determine files Vs.
|
||||
directories, which is achievable using the <code>FileInfo</code> objects.
|
||||
</para>
|
||||
<para><emphasis role="bold">get</emphasis></para>
|
||||
<para>
|
||||
<emphasis>get</emphasis> retrieves a remote file and supports the following option:
|
||||
@@ -435,6 +443,27 @@ xsi:schemaLocation="http://www.springframework.org/schema/integration/sftp
|
||||
for the filenames is
|
||||
provided in the <classname>file_remoteFile</classname> header.
|
||||
</para>
|
||||
<note>
|
||||
<title>Notes for when using recursion (<code>-R</code>)</title>
|
||||
<para>
|
||||
The pattern is ignored, and <code>*</code> is assumed. By
|
||||
default, the entire remote tree is retrieved. However, files in the tree can be filtered, by providing a
|
||||
<classname>FileListFilter</classname>; directories in the tree can also be filtered this way.
|
||||
A <classname>FileListFilter</classname> can be provided by reference or by <code>filename-pattern</code>
|
||||
or <code>filename-regex</code> attributes. For example,
|
||||
<code>filename-regex="(subDir|.*1.txt)"</code> will retrieve all files ending with <code>1.txt</code> in the
|
||||
remote directory and the subdirectory <code>subDir</code>. If a subdirectory is filtered, no additional
|
||||
traversal of that subdirectory is performed.
|
||||
</para>
|
||||
<para>
|
||||
The <code>-dirs</code> option is not allowed (the recursive mget uses the recursive <code>ls</code> to
|
||||
obtain the directory tree and the directories themselves cannot be included in the list).
|
||||
</para>
|
||||
<para>
|
||||
Typically, you would use the <code>#remoteDirectory</code> variable in the <code>local-directory-expression</code>
|
||||
so that the remote directory structure is retained locally.
|
||||
</para>
|
||||
</note>
|
||||
<para><emphasis role="bold">rm</emphasis></para>
|
||||
<para>
|
||||
The <emphasis>rm</emphasis> command has no options.
|
||||
@@ -471,6 +500,15 @@ xsi:schemaLocation="http://www.springframework.org/schema/integration/sftp
|
||||
variable is also available, which is particularly useful for <emphasis>mget</emphasis>, for
|
||||
example: <code>local-filename-generator-expression="#remoteFileName.toUpperCase() + headers.foo"</code>
|
||||
</para>
|
||||
<para>
|
||||
The <emphasis>get</emphasis> and <emphasis>mget</emphasis> commands support
|
||||
the <emphasis>local-directory-expression</emphasis> attribute. It
|
||||
defines a SpEL expression to generate the name of local directory(ies) during the transfer.
|
||||
The root object of the evaluation context is the request Message but, in addition, the <code>remoteDirectory</code>
|
||||
variable is also available, which is particularly useful for <emphasis>mget</emphasis>, for
|
||||
example: <code>local-directory-expression="'/tmp/local/' + #remoteDirectory.toUpperCase() + headers.foo"</code>.
|
||||
This attribute is mutually exclusive with <emphasis>local-directory</emphasis> attribute.
|
||||
</para>
|
||||
<para>
|
||||
For all commands, the PATH that the command acts on is provided by the 'expression'
|
||||
property of the gateway. For the mget command, the expression might evaluate to '*', meaning
|
||||
|
||||
@@ -155,6 +155,20 @@
|
||||
<section id="3.0-general">
|
||||
<title>General Changes</title>
|
||||
|
||||
<section id="3.0-gateway">
|
||||
<title><gateway> Changes</title>
|
||||
<para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
It is now possible to set common headers across all gateway methods, and more options
|
||||
are provided for adding, to the message, information about which method was invoked.
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
<para>
|
||||
For more information see <xref linkend="gateway"/>.
|
||||
</para>
|
||||
</section>
|
||||
<section id="3.0-corr-endpoint-empty-groups">
|
||||
<title>Aggregator 'empty-group-min-timeout' property</title>
|
||||
<para><classname>AbstractCorrelatingMessageHandler</classname> provides a new property
|
||||
@@ -238,14 +252,28 @@
|
||||
<section id="3.0-xFTP-gw">
|
||||
<title>FTP, SFTP and FTPS Gateways</title>
|
||||
<para>
|
||||
The gateways now support the <code>mv</code> command, enabling the renaming of remote
|
||||
files.
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
The gateways now support the <code>mv</code> command, enabling the renaming of remote
|
||||
files.
|
||||
</listitem>
|
||||
<listitem>
|
||||
The gateways now support recursive <code>ls</code> and <code>mget</code> commands, enabling
|
||||
the retrieval of a remote file tree.
|
||||
</listitem>
|
||||
<listitem>
|
||||
The <code>local-filename-generator-expression</code> attribute is now supported,
|
||||
enabling the naming of local files during transfer. By default, the same
|
||||
name as the remote file is used.
|
||||
</listitem>
|
||||
<listitem>
|
||||
The <code>local-directory-expression</code> attribute is now supported,
|
||||
enabling the naming of local directories during transfer based on the remote directory.
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
<para>
|
||||
The <code>local-filename-generator-expression</code> attribute is now supported,
|
||||
enabling the naming of local files during transfer. By default, the same
|
||||
name as the remote file is used. For more information, see
|
||||
<xref linkend="ftp-outbound-gateway"/> and <xref linkend="sftp-outbound-gateway"/>.
|
||||
For more information, see <xref linkend="ftp-outbound-gateway"/> and <xref linkend="sftp-outbound-gateway"/>.
|
||||
</para>
|
||||
</section>
|
||||
<section id="3.0-jdbc-mysql-v5_6_4">
|
||||
|
||||
Reference in New Issue
Block a user