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 97d99fa3d6..1e2d89131f 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 @@ -1,5 +1,5 @@ /* - * Copyright 2016 the original author or authors. + * Copyright 2016-2018 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. @@ -26,6 +26,7 @@ import org.springframework.data.mongodb.core.query.Query; import org.springframework.expression.common.LiteralExpression; import org.springframework.integration.dsl.MessageHandlerSpec; import org.springframework.integration.expression.FunctionExpression; +import org.springframework.integration.mongodb.outbound.MessageCollectionCallback; import org.springframework.integration.mongodb.outbound.MongoDbOutboundGateway; import org.springframework.messaging.Message; @@ -33,6 +34,8 @@ import org.springframework.messaging.Message; * A {@link MessageHandlerSpec} extension for the MongoDb Outbound endpoint {@link MongoDbOutboundGateway} * * @author Xavier Padró + * @author Artem Bilan + * * @since 5.0 */ public class MongoDbOutboundGatewaySpec @@ -149,10 +152,26 @@ public class MongoDbOutboundGatewaySpec * @param collectionCallback the {@link CollectionCallback} instance * @param

the type of the message payload. * @return the spec + * @deprecated in favor of {@link #collectionCallback(MessageCollectionCallback)} */ + @Deprecated public

MongoDbOutboundGatewaySpec collectionCallback(CollectionCallback

collectionCallback) { this.target.setCollectionCallback(collectionCallback); return this; } + /** + * Reference to an instance of {@link MessageCollectionCallback} + * which specifies the database operation to execute in the request message context. + * This property is mutually exclusive with {@link #query} and {@link #queryExpression} properties. + * @param collectionCallback the {@link MessageCollectionCallback} instance + * @param

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

MongoDbOutboundGatewaySpec collectionCallback(MessageCollectionCallback

collectionCallback) { + this.target.setMessageCollectionCallback(collectionCallback); + return this; + } + } diff --git a/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/outbound/MessageCollectionCallback.java b/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/outbound/MessageCollectionCallback.java new file mode 100644 index 0000000000..f64d491f3f --- /dev/null +++ b/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/outbound/MessageCollectionCallback.java @@ -0,0 +1,64 @@ +/* + * Copyright 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.integration.mongodb.outbound; + +import org.bson.Document; + +import org.springframework.dao.DataAccessException; +import org.springframework.data.mongodb.core.CollectionCallback; +import org.springframework.lang.Nullable; +import org.springframework.messaging.Message; + +import com.mongodb.MongoException; +import com.mongodb.client.MongoCollection; + +/** + * The callback to be used with the {@link MongoDbOutboundGateway} + * as an alternative to other query options on the gateway. + *

+ * Plays the same role as standard {@link CollectionCallback}, + * but with {@code Message requestMessage} context during {@code handleMessage()} + * process in the {@link MongoDbOutboundGateway}. + * + * @author Artem Bilan + * + * @since 5.0.11 + * + * @see CollectionCallback + */ +@FunctionalInterface +public interface MessageCollectionCallback extends CollectionCallback { + + /** + * Perform a Mongo operation in the collection using request message as a context. + * @param collection never {@literal null}. + * @param requestMessage the request message ot use for operations + * @return can be {@literal null}. + * @throws MongoException the MongoDB-specific exception + * @throws DataAccessException the data access exception + */ + @Nullable + T doInCollection(MongoCollection collection, Message requestMessage) + throws MongoException, DataAccessException; + + @Override + default T doInCollection(MongoCollection collection) throws MongoException, DataAccessException { + throw new UnsupportedOperationException("The 'doInCollection(MongoCollection, Message)' " + + "must be implemented instead."); + } + +} 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 af53b2a649..58ecf59c7d 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 @@ -1,5 +1,5 @@ /* - * Copyright 2016 the original author or authors. + * Copyright 2016-2018 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. @@ -41,6 +41,8 @@ import org.springframework.util.Assert; * Makes outbound operations to query a MongoDb database using a {@link MongoOperations} * * @author Xavier Padró + * @author Artem Bilan + * * @since 5.0 */ public class MongoDbOutboundGateway extends AbstractReplyProducingMessageHandler { @@ -55,7 +57,7 @@ public class MongoDbOutboundGateway extends AbstractReplyProducingMessageHandler private Expression queryExpression; - private CollectionCallback collectionCallback; + private MessageCollectionCallback collectionCallback; private boolean expectSingleResult = false; @@ -90,8 +92,29 @@ public class MongoDbOutboundGateway extends AbstractReplyProducingMessageHandler this.queryExpression = EXPRESSION_PARSER.parseExpression(queryExpressionString); } + /** + * Specify a {@link CollectionCallback} to perform against MongoDB collection. + * @param collectionCallback the callback to perform against MongoDB collection. + * @deprecated in favor of {@link #setMessageCollectionCallback(MessageCollectionCallback)}. + * Will be removed in 5.2 + */ + @Deprecated public void setCollectionCallback(CollectionCallback collectionCallback) { - Assert.notNull(collectionCallback, "collectionCallback must not be null."); + Assert.notNull(collectionCallback, "'collectionCallback' must not be null."); + this.collectionCallback = + collectionCallback instanceof MessageCollectionCallback + ? (MessageCollectionCallback) collectionCallback + : (collection, requestMessage) -> collectionCallback.doInCollection(collection); + } + + /** + * Specify a {@link MessageCollectionCallback} to perform against MongoDB collection + * in the request message context. + * @param collectionCallback the callback to perform against MongoDB collection. + * @since 5.0.11 + */ + public void setMessageCollectionCallback(MessageCollectionCallback collectionCallback) { + Assert.notNull(collectionCallback, "'collectionCallback' must not be null."); this.collectionCallback = collectionCallback; } @@ -152,7 +175,8 @@ public class MongoDbOutboundGateway extends AbstractReplyProducingMessageHandler Object result; if (this.collectionCallback != null) { - result = this.mongoTemplate.execute(collectionName, this.collectionCallback); // NOSONAR + result = this.mongoTemplate.execute(collectionName, // NOSONAR + collection -> this.collectionCallback.doInCollection(collection, requestMessage)); } else { Query query = buildQuery(requestMessage); diff --git a/spring-integration-mongodb/src/main/resources/org/springframework/integration/mongodb/config/spring-integration-mongodb-5.1.xsd b/spring-integration-mongodb/src/main/resources/org/springframework/integration/mongodb/config/spring-integration-mongodb-5.1.xsd index 2567357a9b..a46939bb84 100644 --- a/spring-integration-mongodb/src/main/resources/org/springframework/integration/mongodb/config/spring-integration-mongodb-5.1.xsd +++ b/spring-integration-mongodb/src/main/resources/org/springframework/integration/mongodb/config/spring-integration-mongodb-5.1.xsd @@ -244,7 +244,10 @@ Reference to an instance of - org.springframework.data.mongodb.core.CollectionCallback + org.springframework.data.mongodb.core.CollectionCallback, preferable an + instance of + org.springframework.integration.mongodb.outbound.MessageCollectionCallback + with the request message context. f - .handle(collectionCallbackOutboundGateway(MongoCollection::countDocuments)) + .handle(collectionCallbackOutboundGateway( + (collection, requestMessage) -> collection.countDocuments())) .channel(getResultChannel()); } @@ -389,7 +390,9 @@ public class MongoDbTests extends MongoDbAvailableTests { .entityClass(Person.class); } - private MongoDbOutboundGatewaySpec collectionCallbackOutboundGateway(CollectionCallback collectionCallback) { + private MongoDbOutboundGatewaySpec collectionCallbackOutboundGateway( + MessageCollectionCallback collectionCallback) { + return MongoDb.outboundGateway(mongoDbFactory(), mongoConverter()) .collectionCallback(collectionCallback) .collectionName(COLLECTION_NAME) 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 37f36fc1e9..20640ea97f 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 @@ -37,6 +37,7 @@ import org.springframework.beans.factory.annotation.Autowired; 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.convert.MongoConverter; import org.springframework.data.mongodb.core.query.BasicQuery; import org.springframework.data.mongodb.core.query.Query; @@ -49,18 +50,16 @@ import org.springframework.integration.support.MessageBuilder; import org.springframework.integration.test.util.TestUtils; import org.springframework.messaging.Message; import org.springframework.test.annotation.DirtiesContext; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; - -import com.mongodb.client.MongoCollection; +import org.springframework.test.context.junit4.SpringRunner; /** * @author Xavier Padró - * @author Gary Russell + * @author Gary Rssell + * @author Artem Bilan + * * @since 5.0 */ -@ContextConfiguration -@RunWith(SpringJUnit4ClassRunner.class) +@RunWith(SpringRunner.class) @DirtiesContext public class MongoDbOutboundGatewayTests extends MongoDbAvailableTests { @@ -96,14 +95,12 @@ public class MongoDbOutboundGatewayTests extends MongoDbAvailableTests { mongoTemplate.dropCollection(COLLECTION_NAME); } - @SuppressWarnings("ConstantConditions") @Test @MongoDbAvailable public void testNoFactorySpecified() { - MongoDbFactory nullFactory = null; try { - new MongoDbOutboundGateway(nullFactory); + new MongoDbOutboundGateway((MongoDbFactory) null); Assert.fail("Expected the test case to throw an IllegalArgumentException"); } catch (IllegalArgumentException e) { @@ -111,14 +108,11 @@ public class MongoDbOutboundGatewayTests extends MongoDbAvailableTests { } } - @SuppressWarnings("ConstantConditions") @Test @MongoDbAvailable public void testNoTemplateSpecified() { - MongoOperations mongoTemplate = null; - try { - new MongoDbOutboundGateway(mongoTemplate); + new MongoDbOutboundGateway((MongoTemplate) null); Assert.fail("Expected the test case to throw an IllegalArgumentException"); } catch (IllegalArgumentException e) { @@ -194,7 +188,7 @@ public class MongoDbOutboundGatewayTests extends MongoDbAvailableTests { @Test @MongoDbAvailable - public void testListOfResultsWithQueryExpression() throws Exception { + public void testListOfResultsWithQueryExpression() { Message message = MessageBuilder.withPayload("{}").build(); MongoDbOutboundGateway gateway = createGateway(); gateway.setEntityClass(Person.class); @@ -209,7 +203,7 @@ public class MongoDbOutboundGatewayTests extends MongoDbAvailableTests { @Test @MongoDbAvailable - public void testListOfResultsWithQueryExpressionReturningOneResult() throws Exception { + public void testListOfResultsWithQueryExpressionReturningOneResult() { Message message = MessageBuilder.withPayload("{name : 'Xavi'}").build(); MongoDbOutboundGateway gateway = createGateway(); gateway.setEntityClass(Person.class); @@ -225,7 +219,7 @@ public class MongoDbOutboundGatewayTests extends MongoDbAvailableTests { @Test @MongoDbAvailable - public void testSingleResultWithQueryExpressionAsString() throws Exception { + public void testSingleResultWithQueryExpressionAsString() { Message message = MessageBuilder.withPayload("{name : 'Artem'}").build(); MongoDbOutboundGateway gateway = createGateway(); gateway.setQueryExpression(PARSER.parseExpression("payload")); @@ -241,7 +235,7 @@ public class MongoDbOutboundGatewayTests extends MongoDbAvailableTests { @Test @MongoDbAvailable - public void testSingleResultWithQueryExpressionAsQuery() throws Exception { + public void testSingleResultWithQueryExpressionAsQuery() { Message message = MessageBuilder.withPayload("").build(); MongoDbOutboundGateway gateway = createGateway(); gateway.setQueryExpression(PARSER.parseExpression("new BasicQuery('{''name'' : ''Gary''}')")); @@ -272,7 +266,7 @@ public class MongoDbOutboundGatewayTests extends MongoDbAvailableTests { @Test @MongoDbAvailable - public void testWithNullCollectionNameExpression() throws Exception { + public void testWithNullCollectionNameExpression() { MongoDbOutboundGateway gateway = new MongoDbOutboundGateway(mongoDbFactory); gateway.setBeanFactory(beanFactory); gateway.setQueryExpression(new LiteralExpression("{name : 'Xavi'}")); @@ -289,7 +283,7 @@ public class MongoDbOutboundGatewayTests extends MongoDbAvailableTests { @Test @MongoDbAvailable - public void testWithCollectionNameExpressionSpecified() throws Exception { + public void testWithCollectionNameExpressionSpecified() { Message message = MessageBuilder.withPayload("").build(); MongoDbOutboundGateway gateway = createGateway(); gateway.setQueryExpression(new LiteralExpression("{name : 'Xavi'}")); @@ -308,13 +302,13 @@ public class MongoDbOutboundGatewayTests extends MongoDbAvailableTests { @Test @MongoDbAvailable - public void testWithCollectionCallbackCount() throws Exception { + public void testWithCollectionCallbackCount() { Message message = MessageBuilder.withPayload("").build(); MongoDbOutboundGateway gateway = createGateway(); gateway.setEntityClass(Person.class); gateway.setCollectionNameExpression(new LiteralExpression("data")); - gateway.setCollectionCallback(MongoCollection::countDocuments); + gateway.setMessageCollectionCallback((collection, requestMessage) -> collection.countDocuments()); gateway.afterPropertiesSet(); long result = (long) gateway.handleRequestMessage(message); @@ -324,15 +318,15 @@ public class MongoDbOutboundGatewayTests extends MongoDbAvailableTests { @Test @MongoDbAvailable - public void testWithCollectionCallbackFindOne() throws Exception { - Message message = MessageBuilder.withPayload("").build(); + public void testWithCollectionCallbackFindOne() { + Message message = MessageBuilder.withPayload("Mike").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")); + gateway.setMessageCollectionCallback((collection, requestMessage) -> { + collection.insertOne(new Document("name", requestMessage.getPayload())); return null; }); gateway.afterPropertiesSet(); 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 95ef3d354c..72d4f486ed 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 @@ -23,13 +23,14 @@ 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; import org.springframework.data.mongodb.core.convert.MappingMongoConverter; import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity; import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty; +import org.springframework.integration.mongodb.outbound.MessageCollectionCallback; +import org.springframework.messaging.Message; import com.mongodb.MongoClient; import com.mongodb.MongoException; @@ -66,7 +67,7 @@ public abstract class MongoDbAvailableTests { } } - public Person createPerson() { + protected Person createPerson() { Address address = new Address(); address.setCity("Philadelphia"); address.setStreet("2121 Rawn street"); @@ -78,7 +79,7 @@ public abstract class MongoDbAvailableTests { return person; } - public Person createPerson(String name) { + protected Person createPerson(String name) { Address address = new Address(); address.setCity("Philadelphia"); address.setStreet("2121 Rawn street"); @@ -169,10 +170,12 @@ public abstract class MongoDbAvailableTests { } - public static class TestCollectionCallback implements CollectionCallback { + public static class TestCollectionCallback implements MessageCollectionCallback { @Override - public Long doInCollection(MongoCollection collection) throws MongoException, DataAccessException { + public Long doInCollection(MongoCollection collection, Message message) + throws MongoException, DataAccessException { + return collection.countDocuments(); } diff --git a/src/reference/asciidoc/mongodb.adoc b/src/reference/asciidoc/mongodb.adoc index 652c836e98..4ae9e451a0 100644 --- a/src/reference/asciidoc/mongodb.adoc +++ b/src/reference/asciidoc/mongodb.adoc @@ -224,7 +224,8 @@ The following example shows how to configure a MongoDB inbound channel adapter: As the preceding configuration shows, you configure a MongoDb inbound channel adapter by using the `inbound-channel-adapter` element and providing values for various attributes, such as: * `query`: A JSON query (see http://www.mongodb.org/display/DOCS/Querying[MongoDB Querying]) -* `query-expression`: A SpEL expression that is evaluated to a JSON query string (as the `query` attribute above) or to an instance of `o.s.data.mongodb.core.query.Query`. Mutually exclusive with the `query` attribute. +* `query-expression`: A SpEL expression that is evaluated to a JSON query string (as the `query` attribute above) or to an instance of `o.s.data.mongodb.core.query.Query`. +Mutually exclusive with the `query` attribute. * `entity-class`: The type of the payload object. If not supplied, a `com.mongodb.DBObject` is returned. * `collection-name` or `collection-name-expression`: Identifies the name of the MongoDB collection to use. * `mongodb-factory`: Reference to an instance of `o.s.data.mongodb.MongoDbFactory` @@ -364,6 +365,8 @@ If this attribute is not provided, the default value is `org.bson.Document`. * `query` or `query-expression`: Specifies the MongoDB query. See the 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`. +Preferable an instance of `org.springframework.integration.mongodb.outbound.MessageCollectionCallback` since 5.0.11 with the request message context. +See its Javadocs for more information. NOTE: You can not have both `collection-callback` and any of the query attributes. ==== Configuring with Java Configuration @@ -448,7 +451,7 @@ public class MongoDbJavaApplication { ---- ==== -As an alternate to the `query` and `query-expression` properties, you can specify other database operations by using the `collectionCallback` property. +As an alternate to the `query` and `query-expression` properties, you can specify other database operations by using the `collectionCallback` property as a reference to the `MessageCollectionCallback` functional interface implementation. The following example specifies a count operation: ==== @@ -456,7 +459,7 @@ The following example specifies a count operation: ---- private MongoDbOutboundGatewaySpec collectionCallbackOutboundGateway() { return MongoDb.outboundGateway(this.mongoDbFactory, this.mongoConverter) - .collectionCallback(MongoCollection::count) + .collectionCallback((collection, requestMessage) -> collection.count()) .collectionName("myCollection"); } ----