Merge pull request #674 from markfisher/INT-2798

This commit is contained in:
Gary Russell
2012-11-19 15:40:39 -05:00
14 changed files with 310 additions and 113 deletions

View File

@@ -28,8 +28,8 @@ public class RedisNamespaceHandler extends AbstractIntegrationNamespaceHandler {
public void init() {
registerBeanDefinitionParser("publish-subscribe-channel", new RedisChannelParser());
registerBeanDefinitionParser("inbound-channel-adapter", new RedisInboundChannelAdapterParser());
registerBeanDefinitionParser("store-inbound-channel-adapter", new RedisCollectionInboundChannelAdapterParser());
registerBeanDefinitionParser("store-outbound-channel-adapter", new RedisCollectionOutboundChannelAdapterParser());
registerBeanDefinitionParser("store-inbound-channel-adapter", new RedisStoreInboundChannelAdapterParser());
registerBeanDefinitionParser("store-outbound-channel-adapter", new RedisStoreOutboundChannelAdapterParser());
registerBeanDefinitionParser("outbound-channel-adapter", new RedisOutboundChannelAdapterParser());
}
}

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.integration.redis.config;
import org.w3c.dom.Element;
@@ -27,6 +28,7 @@ import org.springframework.integration.config.xml.AbstractPollingInboundChannelA
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
import org.springframework.integration.redis.inbound.RedisStoreMessageSource;
import org.springframework.util.StringUtils;
/**
* Parser for Redis store inbound adapters
*
@@ -34,7 +36,7 @@ import org.springframework.util.StringUtils;
* @author Gary Russell
* @since 2.2
*/
public class RedisCollectionInboundChannelAdapterParser extends AbstractPollingInboundChannelAdapterParser {
public class RedisStoreInboundChannelAdapterParser extends AbstractPollingInboundChannelAdapterParser {
@Override
protected BeanMetadataElement parseSource(Element element, ParserContext parserContext) {
@@ -43,9 +45,8 @@ public class RedisCollectionInboundChannelAdapterParser extends AbstractPollingI
String connectionFactory = element.getAttribute("connection-factory");
if (StringUtils.hasText(redisTemplate) && StringUtils.hasText(connectionFactory)){
parserContext.getReaderContext().error("Only one of '" + redisTemplate + "' or '"
+ connectionFactory + "' is allowed", element);
+ connectionFactory + "' is allowed.", element);
}
if (StringUtils.hasText(redisTemplate)){
builder.addConstructorArgReference(redisTemplate);
}
@@ -55,18 +56,15 @@ public class RedisCollectionInboundChannelAdapterParser extends AbstractPollingI
}
builder.addConstructorArgReference(connectionFactory);
}
boolean atLeastOneRequired = true;
RootBeanDefinition expressionDef =
IntegrationNamespaceUtils.createExpressionDefinitionFromValueOrExpression("key", "key-expression",
parserContext, element, atLeastOneRequired);
builder.addConstructorArgValue(expressionDef);
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "collection-type");
String beanName = BeanDefinitionReaderUtils.registerWithGeneratedName(
builder.getBeanDefinition(), parserContext.getRegistry());
return new RuntimeBeanReference(beanName);
}
}

View File

@@ -24,7 +24,7 @@ import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.config.ExpressionFactoryBean;
import org.springframework.integration.config.xml.AbstractOutboundChannelAdapterParser;
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
import org.springframework.integration.redis.outbound.RedisCollectionPopulatingMessageHandler;
import org.springframework.integration.redis.outbound.RedisStoreWritingMessageHandler;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
@@ -36,11 +36,11 @@ import org.w3c.dom.Element;
* @author Mark Fisher
* @since 2.2
*/
public class RedisCollectionOutboundChannelAdapterParser extends AbstractOutboundChannelAdapterParser {
public class RedisStoreOutboundChannelAdapterParser extends AbstractOutboundChannelAdapterParser {
@Override
protected AbstractBeanDefinition parseConsumer(Element element, ParserContext parserContext) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(RedisCollectionPopulatingMessageHandler.class);
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(RedisStoreWritingMessageHandler.class);
String redisTemplateRef = element.getAttribute("redis-template");
String connectionFactory = element.getAttribute("connection-factory");

View File

@@ -56,23 +56,24 @@ import org.springframework.util.NumberUtils;
/**
* Implementation of {@link MessageHandler} which writes Message data into a Redis store
* identified by a key {@link String}.
*
* It supports the collection types identified by {@link CollectionType}.
*
* It also supports batch updates and single item entry.
* It supports batch updates or single item entry.
*
* "Batch updates" means that the payload of the Message may be a Map or Collection.
* With such a payload, individual items from it are added to the corresponding Redis store.
* See {@link #handleMessage(Message)} for more details.
* See {@link #handleMessageInternal(Message)} for more details.
*
* You can also choose to persist such a payload as a single item if the {@link #extractPayloadElements}
* property is set to false (default is true).
* You can instead choose to persist such a payload as a single item if the
* {@link #extractPayloadElements} property is set to false (default is true).
*
* @author Oleg Zhurakousky
* @author Gary Russell
* @author Mark Fisher
* @since 2.2
*/
public class RedisCollectionPopulatingMessageHandler extends AbstractMessageHandler {
public class RedisStoreWritingMessageHandler extends AbstractMessageHandler {
private final Log logger = LogFactory.getLog(this.getClass());
@@ -108,7 +109,7 @@ public class RedisCollectionPopulatingMessageHandler extends AbstractMessageHand
*
* @param redisTemplate
*/
public RedisCollectionPopulatingMessageHandler(RedisTemplate<String, ?> redisTemplate) {
public RedisStoreWritingMessageHandler(RedisTemplate<String, ?> redisTemplate) {
Assert.notNull(redisTemplate, "'redisTemplate' must not be null");
this.redisTemplate = redisTemplate;
this.redisTemplateExplicitlySet = true;
@@ -124,7 +125,7 @@ public class RedisCollectionPopulatingMessageHandler extends AbstractMessageHand
* @see #setExtractPayloadElements(boolean)
* @param connectionFactory
*/
public RedisCollectionPopulatingMessageHandler(RedisConnectionFactory connectionFactory) {
public RedisStoreWritingMessageHandler(RedisConnectionFactory connectionFactory) {
Assert.notNull(connectionFactory, "'connectionFactory' must not be null");
this.connectionFactory = connectionFactory;
}
@@ -158,7 +159,7 @@ public class RedisCollectionPopulatingMessageHandler extends AbstractMessageHand
}
/**
* Sets the collection type for this handler as per {@link CollectionType}
* Sets the collection type for this handler as per {@link CollectionType}.
*
* @param collectionType
*/
@@ -170,7 +171,7 @@ public class RedisCollectionPopulatingMessageHandler extends AbstractMessageHand
* Sets the flag signifying that if the payload is a "multivalue" (i.e., Collection or Map),
* it should be saved using addAll/putAll semantics. Default is 'true'.
* If set to 'false' the payload will be saved as a single entry regardless of its type.
* If the payload is not an instance of "multivalue" (i.e., Collection or Map)
* If the payload is not an instance of "multivalue" (i.e., Collection or Map),
* the value of this attribute is meaningless as the payload will always be
* stored as a single entry.
*
@@ -223,29 +224,31 @@ public class RedisCollectionPopulatingMessageHandler extends AbstractMessageHand
}
/**
* Will extract payload from the Message storing it in the collection identified by the
* {@link #collectionType}. The default CollectinType is LIST.
* Will extract the payload from the Message and store it in the collection identified by the
* key (which may be determined by an expression). The type of collection is specified by the
* {@link #collectionType} property. The default CollectionType is LIST.
* <p/>
* The rules for storing payload are:
* The rules for storing the payload are:
* <p/>
* <b>LIST/SET</b>
* If payload is of type Collection and {@link #extractPayloadElements} is 'true' (default),
* the payload will be added using the addAll() method. If {@link #extractPayloadElements} is set to 'false' then,
* regardless of the payload type, the payload will be added using add();
* If the payload is of type Collection and {@link #extractPayloadElements} is 'true' (default),
* the payload will be added using the addAll() method. If {@link #extractPayloadElements}
* is set to 'false', then regardless of the payload type, the payload will be added using add().
* <p/>
* <b>ZSET</b>
* In addition to rules described for LIST/SET, ZSET allows 'score' information
* to be provided. The score can be provided using the {@link RedisHeaders#ZSET_SCORE} message header,
* when the payload is a Collection, or
* by sending a Map as the payload, where the Map 'key' is the value to be saved and the 'value' is
* the score assigned to this value.
* In addition to the rules described for LIST/SET, ZSET allows 'score' information
* to be provided. The score can be provided using the {@link RedisHeaders#ZSET_SCORE} message header
* when the payload is not a Map, or by sending a Map as the payload where each Map 'key' is a
* value to be saved and each corresponding Map 'value' is the score assigned to it.
* If {@link #extractPayloadElements} is set to 'false' the map will be stored as a single entry.
* If the 'score' can not be determined, the default value (1) will be used.
* <p/>
* <b>MAP/PROPERTIES</b>
* You can also store a payload of type Map or Properties following the same rules as above.
* If payload itself needs to be stored as a value of the map/property then the map key must be
* specified via the mapKeyExpression (default {@link RedisHeaders#MAP_KEY} Message header).
* You can also add items to a Map or Properties based store.
* If the payload itself is of type Map or Properties, it can be stored either as a batch or single
* item following the same rules as described above for other collection types.
* If the payload itself needs to be stored as a value of the map/property then the map key
* must be specified via the mapKeyExpression (default {@link RedisHeaders#MAP_KEY} Message header).
*/
@SuppressWarnings("unchecked")
@Override
@@ -259,19 +262,19 @@ public class RedisCollectionPopulatingMessageHandler extends AbstractMessageHand
Assert.state(this.initialized, "handler not initialized - afterPropertiesSet() must be called before the first use");
try {
if (collectionType == CollectionType.ZSET) {
this.handleZset((RedisZSet<Object>) store, message);
this.writeToZset((RedisZSet<Object>) store, message);
}
else if (collectionType == CollectionType.SET) {
this.handleSet((RedisSet<Object>) store, message);
this.writeToSet((RedisSet<Object>) store, message);
}
else if (collectionType == CollectionType.LIST) {
this.handleList((RedisList<Object>) store, message);
this.writeToList((RedisList<Object>) store, message);
}
else if (collectionType == CollectionType.MAP) {
this.handleMap((RedisMap<Object, Object>) store, message);
this.writeToMap((RedisMap<Object, Object>) store, message);
}
else if (collectionType == CollectionType.PROPERTIES) {
this.handleProperties((RedisProperties) store, message);
this.writeToProperties((RedisProperties) store, message);
}
}
catch (Exception e) {
@@ -280,15 +283,13 @@ public class RedisCollectionPopulatingMessageHandler extends AbstractMessageHand
}
@SuppressWarnings("unchecked")
private void handleZset(RedisZSet<Object> zset, final Message<?> message) throws Exception{
private void writeToZset(RedisZSet<Object> zset, final Message<?> message) throws Exception{
final Object payload = message.getPayload();
final BoundZSetOperations<String, Object> ops =
(BoundZSetOperations<String, Object>) this.redisTemplate.boundZSetOps(zset.getKey());
final boolean zsetIncrementHeader = this.extractZsetIncrementHeader(message);
if (this.extractPayloadElements) {
if ((payload instanceof Map<?, ?> && this.isMapValuesOfTypeNumber((Map<?, ?>) payload))) {
if ((payload instanceof Map<?, ?> && this.verifyAllMapValuesOfTypeNumber((Map<?, ?>) payload))) {
final Map<Object, Number> payloadAsMap = (Map<Object, Number>) payload;
this.processInPipeline(new PipelineCallback() {
public void process() {
@@ -328,7 +329,7 @@ public class RedisCollectionPopulatingMessageHandler extends AbstractMessageHand
}
@SuppressWarnings("unchecked")
private void handleList(RedisList<Object> list, Message<?> message) {
private void writeToList(RedisList<Object> list, Message<?> message) {
Object payload = message.getPayload();
if (this.extractPayloadElements) {
if (payload instanceof Collection<?>) {
@@ -344,7 +345,7 @@ public class RedisCollectionPopulatingMessageHandler extends AbstractMessageHand
}
@SuppressWarnings("unchecked")
private void handleSet(final RedisSet<Object> set, Message<?> message) {
private void writeToSet(final RedisSet<Object> set, Message<?> message) {
final Object payload = message.getPayload();
if (this.extractPayloadElements && payload instanceof Collection<?>) {
final BoundSetOperations<String, Object> ops =
@@ -364,7 +365,7 @@ public class RedisCollectionPopulatingMessageHandler extends AbstractMessageHand
}
@SuppressWarnings("unchecked")
private void handleMap(final RedisMap<Object, Object> map, Message<?> message) {
private void writeToMap(final RedisMap<Object, Object> map, Message<?> message) {
final Object payload = message.getPayload();
if (this.extractPayloadElements && payload instanceof Map<?, ?>) {
this.processInPipeline(new PipelineCallback() {
@@ -374,12 +375,12 @@ public class RedisCollectionPopulatingMessageHandler extends AbstractMessageHand
});
}
else {
Object key = this.assertMapEntry(message, false);
Object key = this.determineMapKey(message, false);
map.put(key, payload);
}
}
private void handleProperties(final RedisProperties properties, Message<?> message) {
private void writeToProperties(final RedisProperties properties, Message<?> message) {
final Object payload = message.getPayload();
if (this.extractPayloadElements && payload instanceof Properties) {
this.processInPipeline(new PipelineCallback() {
@@ -389,7 +390,8 @@ public class RedisCollectionPopulatingMessageHandler extends AbstractMessageHand
});
}
else {
Object key = this.assertMapEntry(message, true);
Assert.isInstanceOf(String.class, payload, "For property, payload must be a String.");
Object key = this.determineMapKey(message, true);
properties.put(key, payload);
}
}
@@ -407,14 +409,12 @@ public class RedisCollectionPopulatingMessageHandler extends AbstractMessageHand
}
}
private Object assertMapEntry(Message<?> message, boolean property) {
private Object determineMapKey(Message<?> message, boolean property) {
Object mapKey = this.mapKeyExpression.getValue(this.evaluationContext, message);
Assert.notNull(mapKey, "Cannot determine a map key for the entry. The key is determined by evaluating " +
"the 'mapKeyExpression' property.");
Object payload = message.getPayload();
if (property) {
Assert.isInstanceOf(String.class, mapKey, "For property, key must be a String");
Assert.isInstanceOf(String.class, payload, "For property, payload must be a String");
}
Assert.isTrue(mapKey != null, "Failed to determine the key for the " +
"Redis Map entry. Payload is not a Map and '" + RedisHeaders.MAP_KEY +
@@ -424,7 +424,6 @@ public class RedisCollectionPopulatingMessageHandler extends AbstractMessageHand
private void incrementOrOverwrite(final BoundZSetOperations<String, Object> ops, Object object, Double score,
boolean zsetIncrementScore) {
if (score != null) {
this.doIncrementOrOverwrite(ops, object, score, zsetIncrementScore);
}
@@ -444,10 +443,13 @@ public class RedisCollectionPopulatingMessageHandler extends AbstractMessageHand
}
}
private boolean isMapValuesOfTypeNumber(Map<?,?> map) {
private boolean verifyAllMapValuesOfTypeNumber(Map<?,?> map) {
for (Object value : map.values()) {
if (!(value instanceof Number)) {
logger.warn("Failed to extract payload elements because one of its values '" + value + "' is not of type Number");
if (logger.isWarnEnabled()) {
logger.warn("failed to extract payload elements because '" +
value + "' is not of type Number");
}
return false;
}
}

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.integration.redis.config;
import static org.junit.Assert.assertEquals;
@@ -22,7 +23,9 @@ import static org.junit.Assert.assertTrue;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.support.collections.RedisCollectionFactoryBean.CollectionType;
@@ -39,7 +42,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
*/
@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
public class RedisCollectionInboundChannelAdapterParserTests {
public class RedisStoreInboundChannelAdapterParserTests {
@Autowired
private ApplicationContext context;
@@ -64,4 +67,10 @@ public class RedisCollectionInboundChannelAdapterParserTests {
assertEquals("LIST", ((CollectionType)TestUtils.getPropertyValue(withExternalTemplate, "collectionType")).toString());
assertSame(redisTemplate, TestUtils.getPropertyValue(withExternalTemplate, "redisTemplate"));
}
@Test(expected=BeanDefinitionParsingException.class)
public void testTemplateAndCfMutualExclusivity(){
new ClassPathXmlApplicationContext("inbound-template-cf-fail.xml", this.getClass());
}
}

View File

@@ -31,7 +31,7 @@ import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.data.redis.support.collections.RedisCollectionFactoryBean.CollectionType;
import org.springframework.expression.common.LiteralExpression;
import org.springframework.integration.redis.outbound.RedisCollectionPopulatingMessageHandler;
import org.springframework.integration.redis.outbound.RedisStoreWritingMessageHandler;
import org.springframework.integration.test.util.TestUtils;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@@ -42,7 +42,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
*/
@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
public class RedisCollectionOutboundChannelAdapterParserTests {
public class RedisStoreOutboundChannelAdapterParserTests {
@Autowired
private ApplicationContext context;
@@ -52,8 +52,8 @@ public class RedisCollectionOutboundChannelAdapterParserTests {
@Test
public void validateWithStringTemplate(){
RedisCollectionPopulatingMessageHandler withStringTemplate =
TestUtils.getPropertyValue(context.getBean("withStringTemplate.adapter"), "handler", RedisCollectionPopulatingMessageHandler.class);
RedisStoreWritingMessageHandler withStringTemplate =
TestUtils.getPropertyValue(context.getBean("withStringTemplate.adapter"), "handler", RedisStoreWritingMessageHandler.class);
assertEquals("pepboys", ((LiteralExpression)TestUtils.getPropertyValue(withStringTemplate, "keyExpression")).getExpressionString());
assertEquals("PROPERTIES", ((CollectionType)TestUtils.getPropertyValue(withStringTemplate, "collectionType")).toString());
assertTrue(TestUtils.getPropertyValue(withStringTemplate, "redisTemplate") instanceof StringRedisTemplate);
@@ -61,8 +61,8 @@ public class RedisCollectionOutboundChannelAdapterParserTests {
@Test
public void validateWithStringObjectTemplate(){
RedisCollectionPopulatingMessageHandler withStringObjectTemplate =
TestUtils.getPropertyValue(context.getBean("withStringObjectTemplate.adapter"), "handler", RedisCollectionPopulatingMessageHandler.class);
RedisStoreWritingMessageHandler withStringObjectTemplate =
TestUtils.getPropertyValue(context.getBean("withStringObjectTemplate.adapter"), "handler", RedisStoreWritingMessageHandler.class);
assertEquals("pepboys", ((LiteralExpression)TestUtils.getPropertyValue(withStringObjectTemplate, "keyExpression")).getExpressionString());
assertEquals("PROPERTIES", ((CollectionType)TestUtils.getPropertyValue(withStringObjectTemplate, "collectionType")).toString());
assertFalse(TestUtils.getPropertyValue(withStringObjectTemplate, "redisTemplate") instanceof StringRedisTemplate);
@@ -74,8 +74,8 @@ public class RedisCollectionOutboundChannelAdapterParserTests {
@Test
public void validateWithExternalTemplate(){
RedisCollectionPopulatingMessageHandler withExternalTemplate =
TestUtils.getPropertyValue(context.getBean("withExternalTemplate.adapter"), "handler", RedisCollectionPopulatingMessageHandler.class);
RedisStoreWritingMessageHandler withExternalTemplate =
TestUtils.getPropertyValue(context.getBean("withExternalTemplate.adapter"), "handler", RedisStoreWritingMessageHandler.class);
assertEquals("pepboys", ((LiteralExpression)TestUtils.getPropertyValue(withExternalTemplate, "keyExpression")).getExpressionString());
assertEquals("PROPERTIES", ((CollectionType)TestUtils.getPropertyValue(withExternalTemplate, "collectionType")).toString());
assertSame(redisTemplate, TestUtils.getPropertyValue(withExternalTemplate, "redisTemplate"));

View File

@@ -14,14 +14,14 @@
* limitations under the License.
*/
package org.springframework.integration.redis.config;
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 org.junit.Test;
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.support.collections.RedisList;
@@ -36,7 +36,7 @@ import org.springframework.integration.redis.rules.RedisAvailableTests;
* @author Oleg Zhurakousky
* @since 2.2
*/
public class RedisCollectionInboundChannelAdapterIntegrationTests extends RedisAvailableTests{
public class RedisStoreInboundChannelAdapterIntegrationTests extends RedisAvailableTests{
@Test
@RedisAvailable
@@ -227,8 +227,4 @@ public class RedisCollectionInboundChannelAdapterIntegrationTests extends RedisA
context.close();
}
@Test(expected=BeanDefinitionParsingException.class)
public void testTemplateAndCfMutualExclusivity(){
new ClassPathXmlApplicationContext("inbound-template-cf-fail.xml", this.getClass());
}
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.integration.redis.config;
package org.springframework.integration.redis.outbound;
import static org.junit.Assert.assertEquals;
@@ -47,7 +47,6 @@ import org.springframework.expression.spel.standard.SpelExpression;
import org.springframework.integration.Message;
import org.springframework.integration.MessageChannel;
import org.springframework.integration.MessageHandlingException;
import org.springframework.integration.redis.outbound.RedisCollectionPopulatingMessageHandler;
import org.springframework.integration.redis.rules.RedisAvailable;
import org.springframework.integration.redis.rules.RedisAvailableTests;
import org.springframework.integration.redis.support.RedisHeaders;
@@ -59,7 +58,7 @@ import org.springframework.integration.test.util.TestUtils;
* @author Mark Fisher
* @since 2.2
*/
public class RedisCollectionOutboundChannelAdapterIntegrationTests extends RedisAvailableTests {
public class RedisStoreOutboundChannelAdapterIntegrationTests extends RedisAvailableTests {
@Test
@RedisAvailable
@@ -76,12 +75,31 @@ public class RedisCollectionOutboundChannelAdapterIntegrationTests extends Redis
pepboys.add("Manny");
pepboys.add("Moe");
pepboys.add("Jack");
Message<List<String>> message = MessageBuilder.withPayload(pepboys).setHeader("redis_key", "pepboys").build();
Message<List<String>> message = MessageBuilder.withPayload(pepboys).setHeader(RedisHeaders.KEY, "pepboys").build();
redisChannel.send(message);
assertEquals(3, redisList.size());
}
@Test
@RedisAvailable
public void testListWithKeyAsHeaderSimple(){
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
StringRedisTemplate redisTemplate = new StringRedisTemplate();
RedisList<String> redisList =
new DefaultRedisList<String>("foo", this.initTemplate(jcf, redisTemplate));
assertEquals(0, redisList.size());
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("store-outbound-adapter.xml", this.getClass());
MessageChannel redisChannel = context.getBean("listWithKeyAsHeader", MessageChannel.class);
Message<String> message = MessageBuilder.withPayload("bar").setHeader("redis_key", "foo").build();
redisChannel.send(message);
assertEquals(1, redisList.size());
redisTemplate.delete("foo");
}
@Test
@RedisAvailable
public void testListWithProvidedKey(){
@@ -102,6 +120,116 @@ public class RedisCollectionOutboundChannelAdapterIntegrationTests extends Redis
assertEquals(3, redisList.size());
}
@Test
@RedisAvailable
public void testZsetSimplePayloadIncrement(){
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
StringRedisTemplate redisTemplate = new StringRedisTemplate();
RedisZSet<String> redisZSet =
new DefaultRedisZSet<String>("foo", this.initTemplate(jcf, redisTemplate));
assertEquals(0, redisZSet.size());
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("store-outbound-adapter.xml", this.getClass());
MessageChannel redisChannel = context.getBean("zset", MessageChannel.class);
Message<String> message = MessageBuilder.withPayload("bar").setHeader(RedisHeaders.KEY, "foo").build();
redisChannel.send(message);
assertEquals(1, redisZSet.size());
assertEquals(Double.valueOf(1), redisZSet.score("bar"));
redisChannel.send(message);
assertEquals(1, redisZSet.size());
assertEquals(Double.valueOf(2), redisZSet.score("bar"));
redisTemplate.delete("foo");
}
@Test
@RedisAvailable
public void testZsetSimplePayloadOverwrite(){
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
StringRedisTemplate redisTemplate = new StringRedisTemplate();
RedisZSet<String> redisZSet =
new DefaultRedisZSet<String>("foo", this.initTemplate(jcf, redisTemplate));
assertEquals(0, redisZSet.size());
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("store-outbound-adapter.xml", this.getClass());
MessageChannel redisChannel = context.getBean("zset", MessageChannel.class);
Message<String> message = MessageBuilder.withPayload("bar")
.setHeader(RedisHeaders.KEY, "foo")
.setHeader(RedisHeaders.ZSET_INCREMENT_SCORE, false)
.build();
redisChannel.send(message);
assertEquals(1, redisZSet.size());
assertEquals(Double.valueOf(1), redisZSet.score("bar"));
redisChannel.send(message);
assertEquals(1, redisZSet.size());
assertEquals(Double.valueOf(1), redisZSet.score("bar"));
redisTemplate.delete("foo");
}
@Test
@RedisAvailable
public void testZsetSimplePayloadIncrementBy2(){
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
StringRedisTemplate redisTemplate = new StringRedisTemplate();
RedisZSet<String> redisZSet =
new DefaultRedisZSet<String>("foo", this.initTemplate(jcf, redisTemplate));
assertEquals(0, redisZSet.size());
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("store-outbound-adapter.xml", this.getClass());
MessageChannel redisChannel = context.getBean("zset", MessageChannel.class);
Message<String> message = MessageBuilder.withPayload("bar")
.setHeader(RedisHeaders.KEY, "foo")
.setHeader(RedisHeaders.ZSET_SCORE, 2)
.build();
redisChannel.send(message);
assertEquals(1, redisZSet.size());
assertEquals(Double.valueOf(2), redisZSet.score("bar"));
redisChannel.send(message);
assertEquals(1, redisZSet.size());
assertEquals(Double.valueOf(4), redisZSet.score("bar"));
redisTemplate.delete("foo");
}
@Test
@RedisAvailable
public void testZsetSimplePayloadOverwriteWithHeaderScore(){
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
StringRedisTemplate redisTemplate = new StringRedisTemplate();
RedisZSet<String> redisZSet =
new DefaultRedisZSet<String>("foo", this.initTemplate(jcf, redisTemplate));
assertEquals(0, redisZSet.size());
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("store-outbound-adapter.xml", this.getClass());
MessageChannel redisChannel = context.getBean("zset", MessageChannel.class);
Message<String> message = MessageBuilder.withPayload("bar")
.setHeader(RedisHeaders.KEY, "foo")
.setHeader(RedisHeaders.ZSET_INCREMENT_SCORE, false)
.setHeader(RedisHeaders.ZSET_SCORE, 2)
.build();
redisChannel.send(message);
assertEquals(1, redisZSet.size());
assertEquals(Double.valueOf(2), redisZSet.score("bar"));
redisChannel.send(MessageBuilder.fromMessage(message).setHeader(RedisHeaders.ZSET_SCORE, 15).build());
assertEquals(1, redisZSet.size());
assertEquals(Double.valueOf(15), redisZSet.score("bar"));
redisTemplate.delete("foo");
}
@Test
@RedisAvailable
public void testMapToZsetWithProvidedKey(){
@@ -126,10 +254,26 @@ public class RedisCollectionOutboundChannelAdapterIntegrationTests extends Redis
assertEquals(5, redisZset.size());
assertEquals(1, redisZset.rangeByScore(18, 18).size());
assertEquals(4, redisZset.rangeByScore(18, 19).size());
assertEquals(1, redisZset.rangeByScore(21, 21).size());
RedisCollectionPopulatingMessageHandler handler = context.getBean("mapToZset.handler",
RedisCollectionPopulatingMessageHandler.class);
RedisStoreWritingMessageHandler handler = context.getBean("mapToZset.handler",
RedisStoreWritingMessageHandler.class);
assertEquals("'presidents'", TestUtils.getPropertyValue(handler, "keyExpression", SpelExpression.class).getExpressionString());
// test default (increment by score) behavior
redisChannel.send(message);
assertEquals(5, redisZset.size());
assertEquals(1, redisZset.rangeByScore(36, 36).size());
assertEquals(4, redisZset.rangeByScore(36, 38).size());
assertEquals(1, redisZset.rangeByScore(42, 42).size());
// test overwrite score behavior
presidents.put("Barack Obama", 31);
redisChannel.send(MessageBuilder.fromMessage(message).setHeader(RedisHeaders.ZSET_INCREMENT_SCORE, false).build());
assertEquals(5, redisZset.size());
assertEquals(1, redisZset.rangeByScore(18, 18).size());
assertEquals(4, redisZset.rangeByScore(18, 19).size());
assertEquals(1, redisZset.rangeByScore(31, 31).size());
}
@Test
@@ -155,8 +299,8 @@ public class RedisCollectionOutboundChannelAdapterIntegrationTests extends Redis
assertEquals("Moe", redisMap.get("2"));
assertEquals("Jack", redisMap.get("3"));
RedisCollectionPopulatingMessageHandler handler = context.getBean("mapToMapA.handler",
RedisCollectionPopulatingMessageHandler.class);
RedisStoreWritingMessageHandler handler = context.getBean("mapToMapA.handler",
RedisStoreWritingMessageHandler.class);
assertEquals("pepboys", TestUtils.getPropertyValue(handler, "keyExpression", LiteralExpression.class).getExpressionString());
assertEquals("'foo'", TestUtils.getPropertyValue(handler, "mapKeyExpression", SpelExpression.class).getExpressionString());
}
@@ -279,6 +423,25 @@ public class RedisCollectionOutboundChannelAdapterIntegrationTests extends Redis
assertEquals(3, redisSet.size());
}
@Test
@RedisAvailable
public void testSetWithKeyAsHeaderSimple(){
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
StringRedisTemplate redisTemplate = new StringRedisTemplate();
RedisSet<String> redisSet =
new DefaultRedisSet<String>("foo", this.initTemplate(jcf, redisTemplate));
assertEquals(0, redisSet.size());
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("store-outbound-adapter.xml", this.getClass());
MessageChannel redisChannel = context.getBean("set", MessageChannel.class);
Message<String> message = MessageBuilder.withPayload("foo")
.setHeader(RedisHeaders.KEY, "foo").build();
redisChannel.send(message);
assertEquals(1, redisSet.size());
redisTemplate.delete("foo");
}
@Test
@RedisAvailable
public void testSetWithKeyAsHeaderNotParsed(){
@@ -342,6 +505,28 @@ public class RedisCollectionOutboundChannelAdapterIntegrationTests extends Redis
assertEquals("Jack", redisProperties.get("3"));
}
@Test
@RedisAvailable
public void testPropertiesSimple(){
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
StringRedisTemplate redisTemplate = new StringRedisTemplate();
RedisProperties redisProperties =
new RedisProperties("foo", this.initTemplate(jcf, redisTemplate));
assertEquals(0, redisProperties.size());
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("store-outbound-adapter.xml", this.getClass());
MessageChannel redisChannel = context.getBean("simpleProperty", MessageChannel.class);
Message<String> message = MessageBuilder.withPayload("bar")
.setHeader(RedisHeaders.KEY, "foo")
.setHeader("baz", "qux")
.build();
redisChannel.send(message);
assertEquals("bar", redisProperties.get("qux"));
redisTemplate.delete("foo");
}
private <K,V> RedisTemplate<K,V> initTemplate(RedisConnectionFactory rcf, RedisTemplate<K,V> redisTemplate){
redisTemplate.setConnectionFactory(rcf);
redisTemplate.afterPropertiesSet();

View File

@@ -53,7 +53,7 @@ import org.springframework.integration.support.MessageBuilder;
* @author Gunnar Hillert
* @author Mark Fisher
*/
public class RedisCollectionPopulatingMessageHandlerTests extends RedisAvailableTests{
public class RedisStoreWritingMessageHandlerTests extends RedisAvailableTests{
@Test
@RedisAvailable
@@ -65,8 +65,8 @@ public class RedisCollectionPopulatingMessageHandlerTests extends RedisAvailable
assertEquals(0, redisList.size());
RedisCollectionPopulatingMessageHandler handler =
new RedisCollectionPopulatingMessageHandler(jcf);
RedisStoreWritingMessageHandler handler =
new RedisStoreWritingMessageHandler(jcf);
handler.setKey(key);
handler.afterPropertiesSet();
@@ -93,8 +93,8 @@ public class RedisCollectionPopulatingMessageHandlerTests extends RedisAvailable
assertEquals(0, redisList.size());
RedisCollectionPopulatingMessageHandler handler =
new RedisCollectionPopulatingMessageHandler(jcf);
RedisStoreWritingMessageHandler handler =
new RedisStoreWritingMessageHandler(jcf);
handler.afterPropertiesSet();
@@ -121,8 +121,8 @@ public class RedisCollectionPopulatingMessageHandlerTests extends RedisAvailable
assertEquals(0, redisList.size());
RedisCollectionPopulatingMessageHandler handler =
new RedisCollectionPopulatingMessageHandler(jcf);
RedisStoreWritingMessageHandler handler =
new RedisStoreWritingMessageHandler(jcf);
handler.afterPropertiesSet();
List<String> list = new ArrayList<String>();
@@ -144,8 +144,8 @@ public class RedisCollectionPopulatingMessageHandlerTests extends RedisAvailable
assertEquals(0, redisList.size());
RedisTemplate<String, List<String>> template = this.initTemplate(jcf, new RedisTemplate<String, List<String>>());
RedisCollectionPopulatingMessageHandler handler =
new RedisCollectionPopulatingMessageHandler(template);
RedisStoreWritingMessageHandler handler =
new RedisStoreWritingMessageHandler(template);
handler.setKey(key);
handler.setExtractPayloadElements(false);
handler.afterPropertiesSet();
@@ -174,8 +174,8 @@ public class RedisCollectionPopulatingMessageHandlerTests extends RedisAvailable
assertEquals(0, redisZset.size());
RedisCollectionPopulatingMessageHandler handler =
new RedisCollectionPopulatingMessageHandler(jcf);
RedisStoreWritingMessageHandler handler =
new RedisStoreWritingMessageHandler(jcf);
handler.setKey(key);
handler.setCollectionType(CollectionType.ZSET);
handler.afterPropertiesSet();
@@ -212,8 +212,8 @@ public class RedisCollectionPopulatingMessageHandlerTests extends RedisAvailable
assertEquals(0, redisZset.size());
RedisCollectionPopulatingMessageHandler handler =
new RedisCollectionPopulatingMessageHandler(jcf);
RedisStoreWritingMessageHandler handler =
new RedisStoreWritingMessageHandler(jcf);
handler.setKey(key);
handler.setCollectionType(CollectionType.ZSET);
handler.afterPropertiesSet();
@@ -253,8 +253,8 @@ public class RedisCollectionPopulatingMessageHandlerTests extends RedisAvailable
assertEquals(0, redisZset.size());
RedisCollectionPopulatingMessageHandler handler =
new RedisCollectionPopulatingMessageHandler(jcf);
RedisStoreWritingMessageHandler handler =
new RedisStoreWritingMessageHandler(jcf);
handler.setKey(key);
handler.setCollectionType(CollectionType.ZSET);
handler.afterPropertiesSet();
@@ -295,8 +295,8 @@ public class RedisCollectionPopulatingMessageHandlerTests extends RedisAvailable
assertEquals(0, redisZset.size());
RedisTemplate<String, List<String>> template = this.initTemplate(jcf, new RedisTemplate<String, List<String>>());
RedisCollectionPopulatingMessageHandler handler =
new RedisCollectionPopulatingMessageHandler(template);
RedisStoreWritingMessageHandler handler =
new RedisStoreWritingMessageHandler(template);
handler.setCollectionType(CollectionType.ZSET);
handler.setExtractPayloadElements(false);
@@ -327,8 +327,8 @@ public class RedisCollectionPopulatingMessageHandlerTests extends RedisAvailable
assertEquals(0, redisZset.size());
RedisCollectionPopulatingMessageHandler handler =
new RedisCollectionPopulatingMessageHandler(jcf);
RedisStoreWritingMessageHandler handler =
new RedisStoreWritingMessageHandler(jcf);
handler.setKey(key);
handler.setCollectionType(CollectionType.ZSET);
handler.afterPropertiesSet();
@@ -370,8 +370,8 @@ public class RedisCollectionPopulatingMessageHandlerTests extends RedisAvailable
assertEquals(0, redisZset.size());
RedisTemplate<String, President> template = this.initTemplate(jcf, new RedisTemplate<String, President>());
RedisCollectionPopulatingMessageHandler handler =
new RedisCollectionPopulatingMessageHandler(template);
RedisStoreWritingMessageHandler handler =
new RedisStoreWritingMessageHandler(template);
handler.setKey(key);
handler.setCollectionType(CollectionType.ZSET);
handler.afterPropertiesSet();
@@ -413,8 +413,8 @@ public class RedisCollectionPopulatingMessageHandlerTests extends RedisAvailable
assertEquals(0, redisZset.size());
RedisTemplate<String, Map<President, Double>> template = this.initTemplate(jcf, new RedisTemplate<String, Map<President, Double>>());
RedisCollectionPopulatingMessageHandler handler =
new RedisCollectionPopulatingMessageHandler(template);
RedisStoreWritingMessageHandler handler =
new RedisStoreWritingMessageHandler(template);
handler.setKey(key);
handler.setCollectionType(CollectionType.ZSET);
handler.setExtractPayloadElements(false);
@@ -437,8 +437,8 @@ public class RedisCollectionPopulatingMessageHandlerTests extends RedisAvailable
public void testListWithMapKeyExpression() {
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
String key = "foo";
RedisCollectionPopulatingMessageHandler handler =
new RedisCollectionPopulatingMessageHandler(jcf);
RedisStoreWritingMessageHandler handler =
new RedisStoreWritingMessageHandler(jcf);
handler.setKey(key);
handler.setMapKeyExpression(new LiteralExpression(key));
handler.afterPropertiesSet();
@@ -449,8 +449,8 @@ public class RedisCollectionPopulatingMessageHandlerTests extends RedisAvailable
public void testSetWithMapKeyExpression() {
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
String key = "foo";
RedisCollectionPopulatingMessageHandler handler =
new RedisCollectionPopulatingMessageHandler(jcf);
RedisStoreWritingMessageHandler handler =
new RedisStoreWritingMessageHandler(jcf);
handler.setKey(key);
handler.setCollectionType(CollectionType.SET);
handler.setMapKeyExpression(new LiteralExpression(key));
@@ -462,8 +462,8 @@ public class RedisCollectionPopulatingMessageHandlerTests extends RedisAvailable
public void testZsetWithMapKeyExpression() {
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
String key = "foo";
RedisCollectionPopulatingMessageHandler handler =
new RedisCollectionPopulatingMessageHandler(jcf);
RedisStoreWritingMessageHandler handler =
new RedisStoreWritingMessageHandler(jcf);
handler.setKey(key);
handler.setCollectionType(CollectionType.ZSET);
handler.setMapKeyExpression(new LiteralExpression(key));
@@ -475,8 +475,8 @@ public class RedisCollectionPopulatingMessageHandlerTests extends RedisAvailable
public void testMapWithMapKeyExpression() {
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
String key = "foo";
RedisCollectionPopulatingMessageHandler handler =
new RedisCollectionPopulatingMessageHandler(jcf);
RedisStoreWritingMessageHandler handler =
new RedisStoreWritingMessageHandler(jcf);
handler.setKey(key);
handler.setCollectionType(CollectionType.MAP);
handler.setMapKeyExpression(new LiteralExpression(key));
@@ -493,8 +493,8 @@ public class RedisCollectionPopulatingMessageHandlerTests extends RedisAvailable
public void testPropertiesWithMapKeyExpression() {
JedisConnectionFactory jcf = this.getConnectionFactoryForTest();
String key = "foo";
RedisCollectionPopulatingMessageHandler handler =
new RedisCollectionPopulatingMessageHandler(jcf);
RedisStoreWritingMessageHandler handler =
new RedisStoreWritingMessageHandler(jcf);
handler.setKey(key);
handler.setCollectionType(CollectionType.PROPERTIES);
handler.setMapKeyExpression(new LiteralExpression(key));

View File

@@ -28,6 +28,9 @@
collection-type="ZSET"
key-expression="'presidents'"/>
<int-redis:store-outbound-channel-adapter id="zset"
collection-type="ZSET"/>
<int-redis:store-outbound-channel-adapter id="mapToMapA"
collection-type="MAP"
map-key-expression="'foo'"
@@ -54,6 +57,10 @@
collection-type="PROPERTIES"
key="pepboys"/>
<int-redis:store-outbound-channel-adapter id="simpleProperty"
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>