INT-4196: MongoOutGateway: add CollectionCallback

JIRA: https://jira.spring.io/browse/INT-4196

Add `CollectionCallback` option to the `MongoDbOutboundGateway`

Add XML support to CollectionCallback

Fix PR comments

Fix issue with javadoc parsing

* Polishing code style, JavaDocs and some Docs
This commit is contained in:
Xavier Padro
2016-12-27 12:41:54 +01:00
committed by Artem Bilan
parent d973295631
commit 739ebb744b
15 changed files with 364 additions and 41 deletions

View File

@@ -39,11 +39,24 @@
request-channel="in"
reply-channel="out"/>
<int-mongodb:outbound-gateway id="fullConfigWithMongoDbCollectionCallback"
mongo-template="mongoDbTemplate"
collection-name="foo"
collection-callback="mockCollectionCallback"
request-channel="in"
reply-channel="out"/>
<bean id="mockCollectionCallback" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="org.springframework.data.mongodb.core.CollectionCallback"/>
</bean>
<bean id="mongoDbFactory" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="org.springframework.data.mongodb.MongoDbFactory"/>
</bean>
<bean id="mongoConverter" class="org.springframework.integration.mongodb.rules.MongoDbAvailableTests.TestMongoConverter">
<bean id="mongoConverter"
class="org.springframework.integration.mongodb.rules.MongoDbAvailableTests.TestMongoConverter">
<constructor-arg ref="mongoDbFactory"/>
<constructor-arg>
<bean class="org.springframework.data.mongodb.core.mapping.MongoMappingContext"/>

View File

@@ -16,11 +16,12 @@
package org.springframework.integration.mongodb.config;
import static org.junit.Assert.assertEquals;
import static org.hamcrest.Matchers.instanceOf;
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 static org.junit.Assert.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -30,6 +31,7 @@ import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.CollectionCallback;
import org.springframework.data.mongodb.core.convert.MongoConverter;
import org.springframework.expression.common.LiteralExpression;
import org.springframework.expression.spel.standard.SpelExpression;
@@ -65,7 +67,8 @@ public class MongoDbOutboundGatewayParserTests {
assertNotNull(TestUtils.getPropertyValue(gateway, "mongoTemplate"));
assertSame(this.mongoDbFactory, TestUtils.getPropertyValue(gateway, "mongoDbFactory"));
assertNotNull(TestUtils.getPropertyValue(gateway, "evaluationContext"));
assertTrue(TestUtils.getPropertyValue(gateway, "collectionNameExpression") instanceof LiteralExpression);
assertThat(TestUtils.getPropertyValue(gateway, "collectionNameExpression"),
instanceOf(LiteralExpression.class));
assertEquals("foo", TestUtils.getPropertyValue(gateway, "collectionNameExpression.literalValue"));
}
@@ -78,7 +81,8 @@ public class MongoDbOutboundGatewayParserTests {
assertSame(this.mongoDbFactory, TestUtils.getPropertyValue(gateway, "mongoDbFactory"));
assertSame(this.mongoConverter, TestUtils.getPropertyValue(gateway, "mongoConverter"));
assertNotNull(TestUtils.getPropertyValue(gateway, "evaluationContext"));
assertTrue(TestUtils.getPropertyValue(gateway, "collectionNameExpression") instanceof SpelExpression);
assertThat(TestUtils.getPropertyValue(gateway, "collectionNameExpression"),
instanceOf(SpelExpression.class));
assertEquals("headers.collectionName",
TestUtils.getPropertyValue(gateway, "collectionNameExpression.expression"));
}
@@ -92,7 +96,8 @@ public class MongoDbOutboundGatewayParserTests {
assertSame(this.mongoDbFactory, TestUtils.getPropertyValue(gateway, "mongoDbFactory"));
assertSame(this.mongoConverter, TestUtils.getPropertyValue(gateway, "mongoConverter"));
assertNotNull(TestUtils.getPropertyValue(gateway, "evaluationContext"));
assertTrue(TestUtils.getPropertyValue(gateway, "collectionNameExpression") instanceof LiteralExpression);
assertThat(TestUtils.getPropertyValue(gateway, "collectionNameExpression"),
instanceOf(LiteralExpression.class));
assertEquals("foo", TestUtils.getPropertyValue(gateway, "collectionNameExpression.literalValue"));
}
@@ -101,14 +106,31 @@ public class MongoDbOutboundGatewayParserTests {
MongoDbOutboundGateway gateway = TestUtils.getPropertyValue(
context.getBean("fullConfigWithTemplate"), "handler", MongoDbOutboundGateway.class);
assertEquals(context.getBean("mongoDbTemplate"), TestUtils.getPropertyValue(gateway, "mongoTemplate"));
assertSame(context.getBean("mongoDbTemplate"), TestUtils.getPropertyValue(gateway, "mongoTemplate"));
assertNull(TestUtils.getPropertyValue(gateway, "mongoDbFactory"));
assertNull(TestUtils.getPropertyValue(gateway, "mongoConverter"));
assertNotNull(TestUtils.getPropertyValue(gateway, "evaluationContext"));
assertTrue(TestUtils.getPropertyValue(gateway, "collectionNameExpression") instanceof LiteralExpression);
assertThat(TestUtils.getPropertyValue(gateway, "collectionNameExpression"),
instanceOf(LiteralExpression.class));
assertEquals("foo", TestUtils.getPropertyValue(gateway, "collectionNameExpression.literalValue"));
}
@Test
public void fullConfigWithMongoDbCollectionCallback() {
MongoDbOutboundGateway gateway = TestUtils.getPropertyValue(
context.getBean("fullConfigWithMongoDbCollectionCallback"), "handler", MongoDbOutboundGateway.class);
assertSame(context.getBean("mongoDbTemplate"), TestUtils.getPropertyValue(gateway, "mongoTemplate"));
assertNull(TestUtils.getPropertyValue(gateway, "mongoDbFactory"));
assertNull(TestUtils.getPropertyValue(gateway, "mongoConverter"));
assertNotNull(TestUtils.getPropertyValue(gateway, "evaluationContext"));
assertThat(TestUtils.getPropertyValue(gateway, "collectionNameExpression"),
instanceOf(LiteralExpression.class));
assertEquals("foo", TestUtils.getPropertyValue(gateway, "collectionNameExpression.literalValue"));
assertThat(TestUtils.getPropertyValue(gateway, "collectionCallback"),
instanceOf(CollectionCallback.class));
}
@Test(expected = BeanDefinitionParsingException.class)
public void templateAndFactoryFail() {
new ClassPathXmlApplicationContext("outbound-gateway-fail-template-factory-config.xml", this.getClass())
@@ -121,4 +143,10 @@ public class MongoDbOutboundGatewayParserTests {
this.getClass()).close();
}
@Test(expected = BeanDefinitionParsingException.class)
public void collectionCallbackAndQueryFail() {
new ClassPathXmlApplicationContext("outbound-gateway-fail-collection-callback-config.xml",
this.getClass()).close();
}
}

View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-mongodb="http://www.springframework.org/schema/integration/mongodb"
xsi:schemaLocation="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
http://www.springframework.org/schema/integration/mongodb http://www.springframework.org/schema/integration/mongodb/spring-integration-mongodb.xsd">
<int:channel id="in"/>
<int:channel id="out"/>
<int-mongodb:outbound-gateway id="gatewayWithCollectionCallbackAndQuery"
mongo-template="mongoDbTemplate"
collection-name="foo"
collection-callback="mockCollectionCallback"
query="{'name' : 'foo'}"
request-channel="in"
reply-channel="out"/>
<bean id="mongoDbFactory" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="org.springframework.data.mongodb.MongoDbFactory"/>
</bean>
<bean id="mongoDbTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg ref="mongoDbFactory"/>
</bean>
<bean id="mockCollectionCallback" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="org.springframework.data.mongodb.core.CollectionCallback"/>
</bean>
</beans>

View File

@@ -32,10 +32,11 @@ import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.BulkOperations;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.BulkOperations;
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.CollectionCallback;
import org.springframework.data.mongodb.core.convert.MongoConverter;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mongodb.core.query.Criteria;
@@ -54,6 +55,7 @@ import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringRunner;
import com.mongodb.MongoClient;
import com.mongodb.client.MongoCollection;
/**
* @author Xavier Padró
@@ -96,6 +98,10 @@ public class MongoDbTests extends MongoDbAvailableTests {
@Qualifier("gatewayCollectionNameFunctionFlow.input")
private MessageChannel gatewayCollectionNameFunctionFlow;
@Autowired
@Qualifier("gatewayCollectionCallbackFlow.input")
private MessageChannel gatewayCollectionCallbackFlow;
@Autowired
private MongoOperations mongoTemplate;
@@ -222,6 +228,20 @@ public class MongoDbTests extends MongoDbAvailableTests {
assertEquals("Gary", person.getName());
}
@Test
@MongoDbAvailable
public void testGatewayWithCollectionCallback() {
gatewayCollectionCallbackFlow.send(MessageBuilder
.withPayload("")
.build());
Message<?> result = this.getResultChannel.receive(10_000);
assertNotNull(result);
long count = (Long) result.getPayload();
assertEquals(4, count);
}
@SuppressWarnings("unchecked")
private List<Person> getPersons(Message<?> message) {
return (List<Person>) message.getPayload();
@@ -290,6 +310,13 @@ public class MongoDbTests extends MongoDbAvailableTests {
.channel(getResultChannel());
}
@Bean
public IntegrationFlow gatewayCollectionCallbackFlow() {
return f -> f
.handle(collectionCallbackOutboundGateway(MongoCollection::count))
.channel(getResultChannel());
}
@Bean
public MessageChannel getResultChannel() {
return MessageChannels.queue().get();
@@ -360,6 +387,13 @@ public class MongoDbTests extends MongoDbAvailableTests {
.entityClass(Person.class);
}
private MongoDbOutboundGatewaySpec collectionCallbackOutboundGateway(CollectionCallback<?> collectionCallback) {
return MongoDb.outboundGateway(mongoDbFactory(), mongoConverter())
.collectionCallback(collectionCallback)
.collectionName(COLLECTION_NAME)
.entityClass(Person.class);
}
}
}

View File

@@ -17,8 +17,9 @@
package org.springframework.integration.mongodb.outbound;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertNotNull;
import java.util.Arrays;
import java.util.List;
@@ -51,6 +52,8 @@ import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.mongodb.client.MongoCollection;
/**
* @author Xavier Padró
* @since 5.0
@@ -134,7 +137,7 @@ public class MongoDbOutboundGatewayTests extends MongoDbAvailableTests {
Assert.fail("Expected the test case to throw an IllegalArgumentException");
}
catch (IllegalStateException e) {
assertEquals("no query specified", e.getMessage());
assertEquals("no query or collectionCallback is specified", e.getMessage());
}
}
@@ -184,7 +187,7 @@ public class MongoDbOutboundGatewayTests extends MongoDbAvailableTests {
Assert.fail("Expected the test case to throw an IllegalStateException");
}
catch (IllegalStateException e) {
assertEquals("no query specified", e.getMessage());
assertEquals("no query or collectionCallback is specified", e.getMessage());
}
}
@@ -302,6 +305,44 @@ public class MongoDbOutboundGatewayTests extends MongoDbAvailableTests {
assertEquals("anotherCollection", collectionNameExpression.getValue());
}
@Test
@MongoDbAvailable
public void testWithCollectionCallbackCount() throws Exception {
Message<String> message = MessageBuilder.withPayload("").build();
MongoDbOutboundGateway gateway = createGateway();
gateway.setEntityClass(Person.class);
gateway.setCollectionNameExpression(new LiteralExpression("data"));
gateway.setCollectionCallback(MongoCollection::count);
gateway.afterPropertiesSet();
long result = (long) gateway.handleRequestMessage(message);
assertEquals(4, result);
}
@Test
@MongoDbAvailable
public void testWithCollectionCallbackFindOne() throws Exception {
Message<String> message = MessageBuilder.withPayload("").build();
MongoDbOutboundGateway gateway = createGateway();
gateway.setEntityClass(Person.class);
gateway.setCollectionNameExpression(new LiteralExpression("data"));
gateway.setRequiresReply(false);
gateway.setCollectionCallback(collection -> {
collection.insertOne(new Document("name", "Mike"));
return null;
});
gateway.afterPropertiesSet();
gateway.handleRequestMessage(message);
List<Person> persons = this.mongoTemplate.find(new Query(), Person.class, COLLECTION_NAME);
assertEquals(5, persons.size());
assertTrue(persons.stream().anyMatch(p -> p.getName().equals("Mike")));
}
@SuppressWarnings("unchecked")
private List<Person> getPersonsFromResult(Object result) {
return (List<Person>) result;

View File

@@ -64,6 +64,15 @@
reply-channel="out"
entity-class="org.springframework.integration.mongodb.rules.MongoDbAvailableTests$Person"/>
<int-mongodb:outbound-gateway id="gatewayCollectionCallback"
mongodb-factory="mongoDbFactory"
mongo-converter="mongoConverter"
collection-callback="countCollectionCallback"
collection-name-expression="headers.collectionName"
request-channel="in"
reply-channel="out"
entity-class="org.springframework.integration.mongodb.rules.MongoDbAvailableTests$Person"/>
<mongo:db-factory id="mongoDbFactory" dbname="test" />
@@ -79,4 +88,7 @@
</constructor-arg>
</bean>
<bean id="countCollectionCallback"
class="org.springframework.integration.mongodb.rules.MongoDbAvailableTests$TestCollectionCallback" />
</beans>

View File

@@ -155,6 +155,24 @@ public class MongoDbOutboundGatewayXmlTests extends MongoDbAvailableTests {
assertEquals(2, persons.size());
}
@Test
@MongoDbAvailable
public void testCollectionCallback() throws Exception {
EventDrivenConsumer consumer = context.getBean("gatewayCollectionCallback", EventDrivenConsumer.class);
PollableChannel outChannel = context.getBean("out", PollableChannel.class);
Message<String> message = MessageBuilder
.withPayload("")
.setHeader("collectionName", "data")
.build();
consumer.getHandler().handleMessage(message);
Message<?> result = outChannel.receive(10000);
long personsCount = (Long) result.getPayload();
assertEquals(4, personsCount);
}
private Person getPerson(Message<?> message) {
return (Person) message.getPayload();
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 the original author or authors.
* Copyright 2002-2016 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,10 +16,14 @@
package org.springframework.integration.mongodb.rules;
import org.bson.Document;
import org.bson.conversions.Bson;
import org.junit.Rule;
import org.springframework.dao.DataAccessException;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.CollectionCallback;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver;
@@ -28,11 +32,14 @@ import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
import com.mongodb.MongoClient;
import com.mongodb.MongoException;
import com.mongodb.client.MongoCollection;
/**
* Convenience base class that enables unit test methods to rely upon the {@link MongoDbAvailable} annotation.
*
* @author Oleg Zhurakousky
* @author Xavier Padró
* @since 2.1
*/
public abstract class MongoDbAvailableTests {
@@ -159,4 +166,13 @@ public abstract class MongoDbAvailableTests {
}
public static class TestCollectionCallback implements CollectionCallback<Long> {
@Override
public Long doInCollection(MongoCollection<Document> collection) throws MongoException, DataAccessException {
return collection.count();
}
}
}