diff --git a/spring-integration-core/src/test/java/org/springframework/integration/configuration/EnableIntegrationTests.java b/spring-integration-core/src/test/java/org/springframework/integration/configuration/EnableIntegrationTests.java index 63391b7d86..6d8ee8e5e3 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/configuration/EnableIntegrationTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/configuration/EnableIntegrationTests.java @@ -950,7 +950,7 @@ public class EnableIntegrationTests { @Bean @ServiceActivator(inputChannel = "controlBusChannel") @Role("bar") - public ExpressionControlBusFactoryBean controlBus() throws Exception { + public ExpressionControlBusFactoryBean controlBus() { return new ExpressionControlBusFactoryBean(); } diff --git a/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/config/MongoDbOutboundGatewayParser.java b/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/config/MongoDbOutboundGatewayParser.java index 16c080bc29..2d9ac9df73 100644 --- a/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/config/MongoDbOutboundGatewayParser.java +++ b/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/config/MongoDbOutboundGatewayParser.java @@ -42,18 +42,28 @@ public class MongoDbOutboundGatewayParser extends AbstractConsumerEndpointParser MongoParserUtils.processCommonAttributes(element, parserContext, builder); IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "reply-timeout"); - String replyChannel = element.getAttribute("reply-channel"); - if (StringUtils.hasText(replyChannel)) { - builder.addPropertyReference("outputChannel", replyChannel); + IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "reply-channel", "outputChannel"); + String collectionCallback = element.getAttribute("collection-callback"); + + if (StringUtils.hasText(collectionCallback)) { + if (StringUtils.hasText(element.getAttribute("query")) || + StringUtils.hasText(element.getAttribute("query-expression"))) { + + parserContext.getReaderContext().error("'collection-callback' is not allowed with " + + "'query' or 'query-expression'", element); + } + + builder.addPropertyReference("collectionCallback", collectionCallback); } + else { + BeanDefinition queryExpressionDef = + IntegrationNamespaceUtils.createExpressionDefinitionFromValueOrExpression("query", + "query-expression", parserContext, element, true); - BeanDefinition queryExpressionDef = - IntegrationNamespaceUtils.createExpressionDefinitionFromValueOrExpression("query", - "query-expression", parserContext, element, true); - - if (queryExpressionDef != null) { - builder.addPropertyValue("queryExpression", queryExpressionDef); + if (queryExpressionDef != null) { + builder.addPropertyValue("queryExpression", queryExpressionDef); + } } IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "expect-single-result"); diff --git a/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/dsl/MongoDb.java b/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/dsl/MongoDb.java index 3007c3a4a1..e83ea17525 100644 --- a/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/dsl/MongoDb.java +++ b/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/dsl/MongoDb.java @@ -28,12 +28,25 @@ import org.springframework.data.mongodb.core.convert.MongoConverter; */ public final class MongoDb { + /** + * Create a {@link MongoDbOutboundGatewaySpec} builder instance + * based on the provided {@link MongoDbFactory} and {@link MongoConverter}. + * @param mongoDbFactory the {@link MongoDbFactory} to use. + * @param mongoConverter the {@link MongoConverter} to use. + * @return the {@link MongoDbOutboundGatewaySpec} instance + */ public static MongoDbOutboundGatewaySpec outboundGateway( MongoDbFactory mongoDbFactory, MongoConverter mongoConverter) { return new MongoDbOutboundGatewaySpec(mongoDbFactory, mongoConverter); } + /** + * Create a {@link MongoDbOutboundGatewaySpec} builder instance + * based on the provided {@link MongoOperations}. + * @param mongoTemplate the {@link MongoOperations} to use. + * @return the {@link MongoDbOutboundGatewaySpec} instance + */ public static MongoDbOutboundGatewaySpec outboundGateway(MongoOperations mongoTemplate) { return new MongoDbOutboundGatewaySpec(mongoTemplate); } diff --git a/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/dsl/MongoDbOutboundGatewaySpec.java b/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/dsl/MongoDbOutboundGatewaySpec.java index 074916009d..97d99fa3d6 100644 --- a/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/dsl/MongoDbOutboundGatewaySpec.java +++ b/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/dsl/MongoDbOutboundGatewaySpec.java @@ -19,6 +19,7 @@ package org.springframework.integration.mongodb.dsl; import java.util.function.Function; import org.springframework.data.mongodb.MongoDbFactory; +import org.springframework.data.mongodb.core.CollectionCallback; import org.springframework.data.mongodb.core.MongoOperations; import org.springframework.data.mongodb.core.convert.MongoConverter; import org.springframework.data.mongodb.core.query.Query; @@ -47,44 +48,111 @@ public class MongoDbOutboundGatewaySpec this.target.setRequiresReply(true); } + /** + * This parameter indicates that only one result object will be returned from the database + * by using a {@code findOne} query. + * If set to {@code false} (default), the complete result list is returned as the payload. + * @param expectSingleResult the {@code boolean} flag to indicate if a single result is returned or not. + * @return the spec + */ public MongoDbOutboundGatewaySpec expectSingleResult(boolean expectSingleResult) { this.target.setExpectSingleResult(expectSingleResult); return this; } + /** + * A {@code String} representation of a MongoDb {@link Query} (e.g., query("{'name' : 'Bob'}")). + * Please refer to MongoDb documentation for more query samples + * see MongoDB Docs + * This property is mutually exclusive with 'queryExpression' property. + * @param query the MongoDb {@link Query} string representation to use. + * @return the spec + */ public MongoDbOutboundGatewaySpec query(String query) { this.target.setQueryExpression(new LiteralExpression(query)); return this; } + /** + * A SpEL expression which should resolve to a {@code String} query (please refer to the 'query' property), + * or to an instance of MongoDb {@link Query} + * (e.q., queryExpression("new BasicQuery('{''address.state'' : ''PA''}')")). + * @param queryExpression the SpEL expression query to use. + * @return the spec + */ public MongoDbOutboundGatewaySpec queryExpression(String queryExpression) { this.target.setQueryExpressionString(queryExpression); return this; } + /** + * A {@link Function} which should resolve to a {@link Query} instance. + * @param queryFunction the {@link Function} to use. + * @param

the type of the message payload. + * @return the spec + */ public

MongoDbOutboundGatewaySpec queryFunction(Function, Query> queryFunction) { this.target.setQueryExpression(new FunctionExpression<>(queryFunction)); return this; } + /** + * The fully qualified name of the entity class to be passed + * to {@code find(..)} or {@code findOne(..)} method in {@link MongoOperations}. + * If this attribute is not provided the default value is {@link org.bson.Document}. + * @param entityClass the {@link Class} to use. + * @return the spec + */ public MongoDbOutboundGatewaySpec entityClass(Class entityClass) { this.target.setEntityClass(entityClass); return this; } + /** + * Identify the name of the MongoDb collection to use. + * This attribute is mutually exclusive with {@link #collectionNameExpression} property. + * @param collectionName the {@link String} specifying the MongoDb collection. + * @return the spec + */ public MongoDbOutboundGatewaySpec collectionName(String collectionName) { this.target.setCollectionNameExpression(new LiteralExpression(collectionName)); return this; } + /** + * A SpEL expression which should resolve to a {@link String} value + * identifying the name of the MongoDb collection to use. + * This property is mutually exclusive with {@link #collectionName} property. + * @param collectionNameExpression the {@link String} expression to use. + * @return the spec + */ public MongoDbOutboundGatewaySpec collectionNameExpression(String collectionNameExpression) { this.target.setCollectionNameExpressionString(collectionNameExpression); return this; } + /** + * A {@link Function} which should resolve to a {@link String} + * (e.q., {@code collectionNameFunction(Message::getPayload)}). + * @param collectionNameFunction the {@link Function} to use. + * @param

the type of the message payload. + * @return the spec + */ public

MongoDbOutboundGatewaySpec collectionNameFunction(Function, String> collectionNameFunction) { this.target.setCollectionNameExpression(new FunctionExpression<>(collectionNameFunction)); return this; } + /** + * Reference to an instance of {@link CollectionCallback} which specifies the database operation to execute. + * This property is mutually exclusive with {@link #query} and {@link #queryExpression} properties. + * @param collectionCallback the {@link CollectionCallback} instance + * @param

the type of the message payload. + * @return the spec + */ + public

MongoDbOutboundGatewaySpec collectionCallback(CollectionCallback

collectionCallback) { + this.target.setCollectionCallback(collectionCallback); + return this; + } + } diff --git a/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/outbound/MongoDbOutboundGateway.java b/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/outbound/MongoDbOutboundGateway.java index 048339c3d5..22b7e763a0 100644 --- a/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/outbound/MongoDbOutboundGateway.java +++ b/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/outbound/MongoDbOutboundGateway.java @@ -19,6 +19,7 @@ package org.springframework.integration.mongodb.outbound; import org.bson.Document; import org.springframework.data.mongodb.MongoDbFactory; +import org.springframework.data.mongodb.core.CollectionCallback; import org.springframework.data.mongodb.core.MongoOperations; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver; @@ -54,6 +55,8 @@ public class MongoDbOutboundGateway extends AbstractReplyProducingMessageHandler private Expression queryExpression; + private CollectionCallback collectionCallback; + private boolean expectSingleResult = false; private Class entityClass = Document.class; @@ -87,6 +90,11 @@ public class MongoDbOutboundGateway extends AbstractReplyProducingMessageHandler this.queryExpression = EXPRESSION_PARSER.parseExpression(queryExpressionString); } + public void setCollectionCallback(CollectionCallback collectionCallback) { + Assert.notNull(collectionCallback, "collectionCallback must not be null."); + this.collectionCallback = collectionCallback; + } + public void setExpectSingleResult(boolean expectSingleResult) { this.expectSingleResult = expectSingleResult; } @@ -115,8 +123,12 @@ public class MongoDbOutboundGateway extends AbstractReplyProducingMessageHandler @Override protected void doInit() { - Assert.state(this.queryExpression != null, "no query specified"); + Assert.state(this.queryExpression != null || this.collectionCallback != null, + "no query or collectionCallback is specified"); Assert.state(this.collectionNameExpression != null, "no collection name specified"); + if (this.queryExpression != null && this.collectionCallback != null) { + throw new IllegalStateException("query and collectionCallback are mutually exclusive"); + } if (this.evaluationContext == null) { this.evaluationContext = ExpressionUtils.createStandardEvaluationContext(this.getBeanFactory()); @@ -136,15 +148,21 @@ public class MongoDbOutboundGateway extends AbstractReplyProducingMessageHandler protected Object handleRequestMessage(Message requestMessage) { String collectionName = this.collectionNameExpression.getValue(this.evaluationContext, requestMessage, String.class); - Query query = buildQuery(requestMessage); Object result; - if (this.expectSingleResult) { - result = this.mongoTemplate.findOne(query, this.entityClass, collectionName); + if (this.collectionCallback != null) { + result = this.mongoTemplate.execute(collectionName, this.collectionCallback); } else { - result = this.mongoTemplate.find(query, this.entityClass, collectionName); + Query query = buildQuery(requestMessage); + + if (this.expectSingleResult) { + result = this.mongoTemplate.findOne(query, this.entityClass, collectionName); + } + else { + result = this.mongoTemplate.find(query, this.entityClass, collectionName); + } } return result; diff --git a/spring-integration-mongodb/src/main/resources/org/springframework/integration/mongodb/config/spring-integration-mongodb-5.0.xsd b/spring-integration-mongodb/src/main/resources/org/springframework/integration/mongodb/config/spring-integration-mongodb-5.0.xsd index 34fa7a96a7..80e176ff22 100644 --- a/spring-integration-mongodb/src/main/resources/org/springframework/integration/mongodb/config/spring-integration-mongodb-5.0.xsd +++ b/spring-integration-mongodb/src/main/resources/org/springframework/integration/mongodb/config/spring-integration-mongodb-5.0.xsd @@ -234,6 +234,20 @@ + + + + + Reference to an instance of + org.springframework.data.mongodb.core.CollectionCallback + + + + + + + diff --git a/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/MongoDbOutboundGatewayParserTests-context.xml b/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/MongoDbOutboundGatewayParserTests-context.xml index 59e143acba..f622f5ac27 100644 --- a/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/MongoDbOutboundGatewayParserTests-context.xml +++ b/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/MongoDbOutboundGatewayParserTests-context.xml @@ -39,11 +39,24 @@ request-channel="in" reply-channel="out"/> + + + + + + + - + diff --git a/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/MongoDbOutboundGatewayParserTests.java b/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/MongoDbOutboundGatewayParserTests.java index 3fae4305c5..de199f5c3e 100644 --- a/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/MongoDbOutboundGatewayParserTests.java +++ b/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/MongoDbOutboundGatewayParserTests.java @@ -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(); + } + } diff --git a/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/outbound-gateway-fail-collection-callback-config.xml b/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/outbound-gateway-fail-collection-callback-config.xml new file mode 100644 index 0000000000..76d0a2c22a --- /dev/null +++ b/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/outbound-gateway-fail-collection-callback-config.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/dsl/MongoDbTests.java b/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/dsl/MongoDbTests.java index ca72f5a15b..2553f242e3 100644 --- a/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/dsl/MongoDbTests.java +++ b/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/dsl/MongoDbTests.java @@ -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 getPersons(Message message) { return (List) 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); + } + } } diff --git a/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/outbound/MongoDbOutboundGatewayTests.java b/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/outbound/MongoDbOutboundGatewayTests.java index b9d4ddd34f..c08204d40f 100644 --- a/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/outbound/MongoDbOutboundGatewayTests.java +++ b/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/outbound/MongoDbOutboundGatewayTests.java @@ -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 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 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 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 getPersonsFromResult(Object result) { return (List) result; diff --git a/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/outbound/MongoDbOutboundGatewayXmlTests-context.xml b/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/outbound/MongoDbOutboundGatewayXmlTests-context.xml index 1a20cd2ad3..4cdb879253 100644 --- a/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/outbound/MongoDbOutboundGatewayXmlTests-context.xml +++ b/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/outbound/MongoDbOutboundGatewayXmlTests-context.xml @@ -64,6 +64,15 @@ reply-channel="out" entity-class="org.springframework.integration.mongodb.rules.MongoDbAvailableTests$Person"/> + + @@ -79,4 +88,7 @@ + + diff --git a/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/outbound/MongoDbOutboundGatewayXmlTests.java b/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/outbound/MongoDbOutboundGatewayXmlTests.java index 8dff1443f1..eb5230d083 100644 --- a/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/outbound/MongoDbOutboundGatewayXmlTests.java +++ b/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/outbound/MongoDbOutboundGatewayXmlTests.java @@ -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 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(); } diff --git a/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/rules/MongoDbAvailableTests.java b/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/rules/MongoDbAvailableTests.java index 079cb18ff3..f8aa7a2727 100644 --- a/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/rules/MongoDbAvailableTests.java +++ b/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/rules/MongoDbAvailableTests.java @@ -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 { + + @Override + public Long doInCollection(MongoCollection collection) throws MongoException, DataAccessException { + return collection.count(); + } + + } + } diff --git a/src/reference/asciidoc/mongodb.adoc b/src/reference/asciidoc/mongodb.adoc index 682750df35..5ab8537fdf 100644 --- a/src/reference/asciidoc/mongodb.adoc +++ b/src/reference/asciidoc/mongodb.adoc @@ -318,6 +318,8 @@ The Message payload and headers can be used to specify the query, as well as col If this attribute is not provided the default value is `org.bson.Document`; * `query` or `query-expression` - specifies the MongoDb query. Please refer to http://www.mongodb.org/display/DOCS/Querying[MongoDB documentation] for more query samples. +* `collection-callback` - reference to an instance of `org.springframework.data.mongodb.core.CollectionCallback` +(NOTE: you can not have both collection-callback and any of the query attributes). ==== Configuring with Java Configuration @@ -337,16 +339,6 @@ public class MongoDbJavaApplication { @Autowired private MongoDbFactory mongoDbFactory; - @Bean - public MessageChannel requestChannel() { - return new DirectChannel(); - } - - @Bean - public MessageChannel replyChannel() { - return new QueueChannel(5); - } - @Bean @ServiceActivator(inputChannel = "requestChannel") public MessageHandler mongoDbOutboundGateway() { @@ -356,7 +348,6 @@ public class MongoDbJavaApplication { gateway.setExpectSingleResult(true); gateway.setEntityClass(Person.class); gateway.setOutputChannelName("replyChannel"); - return gateway; } @@ -406,4 +397,17 @@ public class MongoDbJavaApplication { } } +---- + +Alternatively to the `query` and `query-expression` properties, you can specify other database operations through +the `collectionCallback` property. +The following example specifies a count operation: + +[source, java] +---- +private MongoDbOutboundGatewaySpec collectionCallbackOutboundGateway() { + return MongoDb.outboundGateway(this.mongoDbFactory, this.mongoConverter) + .collectionCallback(MongoCollection::count) + .collectionName("foo"); + } ---- \ No newline at end of file