diff --git a/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/config/MongoDbInboundChannelAdapterParser.java b/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/config/MongoDbInboundChannelAdapterParser.java new file mode 100644 index 0000000000..56b82a1d3e --- /dev/null +++ b/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/config/MongoDbInboundChannelAdapterParser.java @@ -0,0 +1,59 @@ +/* + * Copyright 2002-2012 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.config; + +import org.w3c.dom.Element; + +import org.springframework.beans.BeanMetadataElement; +import org.springframework.beans.factory.config.RuntimeBeanReference; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.integration.config.xml.AbstractPollingInboundChannelAdapterParser; +import org.springframework.integration.config.xml.IntegrationNamespaceUtils; +import org.springframework.integration.mongodb.inbound.MongoDbMessageSource; +/** + * Parser for Mongodb store inbound adapters + * + * @author Amol Nayak + * @author Oleg Zhurakousky + * @since 2.2 + */ +public class MongoDbInboundChannelAdapterParser extends AbstractPollingInboundChannelAdapterParser { + + @Override + protected BeanMetadataElement parseSource(Element element, ParserContext parserContext) { + BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(MongoDbMessageSource.class); + + // Will parse and validate 'mongodb-template', 'mongodb-factory', + // 'collection-name', 'collection-name-expression' and 'mongo-converter' + MongoParserUtils.processCommonAttributes(element, parserContext, builder); + + RootBeanDefinition queryExpressionDef = + IntegrationNamespaceUtils.createExpressionDefinitionFromValueOrExpression("query", "query-expression", + parserContext, element, true); + + builder.addConstructorArgValue(queryExpressionDef); + + IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "entity-class"); + IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "expect-single-result"); + + String beanName = BeanDefinitionReaderUtils.registerWithGeneratedName( + builder.getBeanDefinition(), parserContext.getRegistry()); + return new RuntimeBeanReference(beanName); + } +} diff --git a/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/config/MongoDbNamespaceHandler.java b/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/config/MongoDbNamespaceHandler.java new file mode 100644 index 0000000000..e5ff963b5d --- /dev/null +++ b/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/config/MongoDbNamespaceHandler.java @@ -0,0 +1,34 @@ +/* + * Copyright 2002-2012 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.config; + +import org.springframework.integration.config.xml.AbstractIntegrationNamespaceHandler; + +/** + * Namespace handler for Spring Integration's 'mongodb' namespace. + * + * @author Amol Nayak + * @author Oleg Zhurakousky + * + * @since 2.2 + */ +public class MongoDbNamespaceHandler extends AbstractIntegrationNamespaceHandler { + + public void init() { + registerBeanDefinitionParser("inbound-channel-adapter", new MongoDbInboundChannelAdapterParser()); + registerBeanDefinitionParser("outbound-channel-adapter", new MongoDbOutboundChannelAdapterParser()); + } +} \ No newline at end of file diff --git a/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/config/MongoDbOutboundChannelAdapterParser.java b/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/config/MongoDbOutboundChannelAdapterParser.java new file mode 100644 index 0000000000..cfa509c9ca --- /dev/null +++ b/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/config/MongoDbOutboundChannelAdapterParser.java @@ -0,0 +1,43 @@ +/* + * Copyright 2007-2012 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.config; + +import org.w3c.dom.Element; + +import org.springframework.beans.factory.support.AbstractBeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.integration.config.xml.AbstractOutboundChannelAdapterParser; +import org.springframework.integration.mongodb.outbound.MongoDbStoringMessageHandler; +/** + * Parser for Mongodb store outbound adapters + * + * @author Oleg Zhurakousky + * @since 2.2 + */ +public class MongoDbOutboundChannelAdapterParser extends AbstractOutboundChannelAdapterParser { + + @Override + protected AbstractBeanDefinition parseConsumer(Element element, ParserContext parserContext) { + BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MongoDbStoringMessageHandler.class); + + // Will parse and validate 'mongodb-template', 'mongodb-factory', + // 'collection-name', 'collection-name-expression' and 'mongo-converter' + MongoParserUtils.processCommonAttributes(element, parserContext, builder); + + return builder.getBeanDefinition(); + } +} \ No newline at end of file diff --git a/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/config/MongoParserUtils.java b/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/config/MongoParserUtils.java new file mode 100644 index 0000000000..5f1bc8941e --- /dev/null +++ b/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/config/MongoParserUtils.java @@ -0,0 +1,75 @@ +/* + * Copyright 2002-2012 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.config; + +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.integration.config.xml.IntegrationNamespaceUtils; +import org.springframework.util.StringUtils; +import org.w3c.dom.Element; +/** + * Utility class used by mongo parsers + * + * @author Oleg Zhurakousky + * @author Gary Russell + * @since 2.2 + */ +class MongoParserUtils { + + /** + * Will parse and validate + * 'mongodb-template', 'mongodb-factory', 'collection-name', 'collection-name-expression' and 'mongo-converter' + * + * @param element + * @param parserContext + * @param builder + */ + public static void processCommonAttributes(Element element, ParserContext parserContext, BeanDefinitionBuilder builder){ + String mongoDbTemplate = element.getAttribute("mongo-template"); + String mongoDbFactory = element.getAttribute("mongodb-factory"); + + if (StringUtils.hasText(mongoDbTemplate) && StringUtils.hasText(mongoDbFactory)){ + parserContext.getReaderContext().error("Only one of '" + mongoDbTemplate + "' or '" + + mongoDbFactory + "' is allowed", element); + } + + if (StringUtils.hasText(mongoDbTemplate)){ + builder.addConstructorArgReference(mongoDbTemplate); + if (StringUtils.hasText(element.getAttribute("mongo-converter"))) { + parserContext.getReaderContext().error("'mongo-converter' is not allowed with 'mongo-template'", + element); + } + } + else { + if (!StringUtils.hasText(mongoDbFactory)) { + mongoDbFactory = "mongoDbFactory"; + } + builder.addConstructorArgReference(mongoDbFactory); + IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "mongo-converter"); + } + + RootBeanDefinition collectionNameExpressionDef = + IntegrationNamespaceUtils.createExpressionDefinitionFromValueOrExpression("collection-name", "collection-name-expression", + parserContext, element, false); + + + if (collectionNameExpressionDef != null){ + builder.addPropertyValue("collectionNameExpression", collectionNameExpressionDef); + } + + } +} diff --git a/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/config/package-info.java b/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/config/package-info.java new file mode 100644 index 0000000000..682a467d53 --- /dev/null +++ b/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/config/package-info.java @@ -0,0 +1,4 @@ +/** + * Contains parser classes for the MongoDb namespace support. + */ +package org.springframework.integration.mongodb.config; \ No newline at end of file diff --git a/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/inbound/MongoDbMessageSource.java b/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/inbound/MongoDbMessageSource.java new file mode 100644 index 0000000000..d07ae89bc2 --- /dev/null +++ b/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/inbound/MongoDbMessageSource.java @@ -0,0 +1,243 @@ +/* + * Copyright 2007-2012 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.inbound; + +import java.util.List; + +import org.springframework.context.MessageSource; +import org.springframework.data.mongodb.MongoDbFactory; +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; +import org.springframework.expression.Expression; +import org.springframework.expression.common.LiteralExpression; +import org.springframework.expression.spel.support.StandardEvaluationContext; +import org.springframework.integration.Message; +import org.springframework.integration.context.IntegrationObjectSupport; +import org.springframework.integration.core.PseudoTransactionalMessageSource; +import org.springframework.integration.mongodb.support.MongoHeaders; +import org.springframework.integration.support.MessageBuilder; +import org.springframework.integration.util.ExpressionUtils; +import org.springframework.util.Assert; +import org.springframework.util.CollectionUtils; + +import com.mongodb.DBObject; + +/** + * An instance of {@link MessageSource} which returns a {@link Message} with a payload + * which is the result of execution of a {@link Query}. When expectSingleResult is false + * (default), + * the MongoDb {@link Query} is executed using {@link MongoOperations#find(Query, Class)} + * method which returns a {@link List}. The returned {@link List} will be used as + * the payoad of the {@link Message} returned by the {{@link #receive()} method. + * An empty {@link List} is treated as null, thus resulting in no {@link Message} returned + * by the {{@link #receive()} method. + *

+ * When expectSingleResult is true, the {@link MongoOperations#findOne(Query, Class)} is + * used instead, and the message payload will be the single object returned from the + * query. + * + * @author Amol Nayak + * @author Oleg Zhurakousky + * + * @since 2.2 + */ +public class MongoDbMessageSource extends IntegrationObjectSupport + implements PseudoTransactionalMessageSource{ + + private final Expression queryExpression; + + private volatile Expression collectionNameExpression = new LiteralExpression("data"); + + private volatile StandardEvaluationContext evaluationContext; + + private volatile MongoOperations mongoTemplate; + + private volatile MongoConverter mongoConverter; + + private volatile MongoDbFactory mongoDbFactory; + + private volatile boolean initialized = false; + + private volatile Class entityClass = DBObject.class; + + private volatile boolean expectSingleResult = false; + + /** + * Creates an instance with the provided {@link MongoDbFactory} and SpEL expression + * which should resolve to a MongoDb 'query' string + * (see http://www.mongodb.org/display/DOCS/Querying). + * The 'queryExpression' will be evaluated on every call to the {@link #receive()} method. + * + * @param mongoDbFactory + * @param queryExpression + */ + public MongoDbMessageSource(MongoDbFactory mongoDbFactory, Expression queryExpression){ + Assert.notNull(mongoDbFactory, "'mongoDbFactory' must not be null"); + Assert.notNull(queryExpression, "'queryExpression' must not be null"); + + this.mongoDbFactory = mongoDbFactory; + this.queryExpression = queryExpression; + } + + /** + * Creates an instance with the provided {@link MongoOperations} and SpEL expression + * which should resolve to a Mongo 'query' string + * (see http://www.mongodb.org/display/DOCS/Querying). + * It assumes that the {@link MongoOperations} is fully initialized and ready to be used. + * The 'queryExpression' will be evaluated on every call to the {@link #receive()} method. + * + * @param mongoTemplate + * @param queryExpression + */ + public MongoDbMessageSource(MongoOperations mongoTemplate, Expression queryExpression){ + Assert.notNull(mongoTemplate, "'mongoTemplate' must not be null"); + Assert.notNull(queryExpression, "'queryExpression' must not be null"); + + this.mongoTemplate = mongoTemplate; + this.queryExpression = queryExpression; + } + + /** + * Allows you to set the type of the entityClass that will be passed to the + * {@link MongoTemplate#find(Query, Class)} or {@link MongoTemplate#findOne(Query, Class)} + * method. + * Default is {@link DBObject}. + * + * @param entityClass + */ + public void setEntityClass(Class entityClass) { + Assert.notNull(entityClass, "'entityClass' must not be null"); + this.entityClass = entityClass; + } + + /** + * Allows you to manage which find* method to invoke on {@link MongoTemplate}. + * Default is 'false', which means the {@link #receive()} method will use + * the {@link MongoTemplate#find(Query, Class)} method. If set to 'true', + * {@link #receive()} will use {@link MongoTemplate#findOne(Query, Class)}, + * and the payload of the returned {@link Message} will be the returned target Object of type + * identified by {{@link #entityClass} instead of a List. + * + * @param expectSingleResult + */ + public void setExpectSingleResult(boolean expectSingleResult) { + this.expectSingleResult = expectSingleResult; + } + + /** + * Sets the SpEL {@link Expression} that should resolve to a collection name + * used by the {@link Query}. The resulting collection name will be included + * in the {@link MongoHeaders#COLLECTION_NAME} header. + * + * @param collectionNameExpression + */ + public void setCollectionNameExpression(Expression collectionNameExpression) { + Assert.notNull(collectionNameExpression, "'collectionNameExpression' must not be null"); + this.collectionNameExpression = collectionNameExpression; + } + + /** + * Allows you to provide a custom {@link MongoConverter} used to assist in deserialization + * data read from MongoDb. Only allowed if this instance was constructed with a + * {@link MongoDbFactory}. + * + * @param mongoConverter + */ + public void setMongoConverter(MongoConverter mongoConverter) { + Assert.isNull(this.mongoTemplate, + "'mongoConverter' can not be set when instance was constructed with MongoTemplate"); + this.mongoConverter = mongoConverter; + } + + @Override + protected void onInit() throws Exception { + if (this.getBeanFactory() != null){ + this.evaluationContext = + ExpressionUtils.createStandardEvaluationContext(this.getBeanFactory()); + } + else { + this.evaluationContext = ExpressionUtils.createStandardEvaluationContext(); + } + + if (this.mongoTemplate == null){ + this.mongoTemplate = new MongoTemplate(this.mongoDbFactory, this.mongoConverter); + } + this.initialized = true; + } + + /** + * Will execute a {@link Query} returning its results as the Message payload. + * The payload can be either {@link List} of elements of objects of type + * identified by {{@link #entityClass}, or a single element of type identified by {{@link #entityClass} + * based on the value of {{@link #expectSingleResult} attribute which defaults to 'false' resulting + * {@link Message} with payload of type {@link List}. The collection name used in the + * query will be provided in the {@link MongoHeaders#COLLECTION_NAME} header. + */ + public Message receive() { + Assert.isTrue(this.initialized, "This class is not yet initialized. Invoke its afterPropertiesSet() method"); + Message message = null; + Query query = new BasicQuery(this.queryExpression.getValue(this.evaluationContext, String.class)); + Assert.notNull(query, "'queryExpression' must not evaluate to null"); + String collectionName = this.collectionNameExpression.getValue(this.evaluationContext, String.class); + Assert.notNull(collectionName, "'collectionNameExpression' must not evaluate to null"); + + Object result = null; + if (this.expectSingleResult){ + result = this.mongoTemplate. + findOne(query, this.entityClass, collectionName); + } + else { + List results = this.mongoTemplate. + find(query, this.entityClass, collectionName); + if (!CollectionUtils.isEmpty(results)){ + result = results; + } + } + if (result != null){ + message = MessageBuilder.withPayload(result) + .setHeader(MongoHeaders.COLLECTION_NAME, collectionName) + .build(); + } + + return message; + } + + /** + * Returns the mongo-template. + */ + public MongoOperations getResource() { + return this.mongoTemplate; + } + + public void afterCommit(Object object) { + + } + + public void afterRollback(Object object) { + + } + + public void afterReceiveNoTx(MongoOperations resource) { + + } + + public void afterSendNoTx(MongoOperations resource) { + + } +} diff --git a/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/inbound/package-info.java b/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/inbound/package-info.java new file mode 100644 index 0000000000..d76784f51e --- /dev/null +++ b/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/inbound/package-info.java @@ -0,0 +1,4 @@ +/** + * Provides classes related to the Mongo inbound channel adapters + */ +package org.springframework.integration.mongodb.inbound; \ No newline at end of file diff --git a/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/outbound/MongoDbStoringMessageHandler.java b/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/outbound/MongoDbStoringMessageHandler.java new file mode 100644 index 0000000000..b55130da3a --- /dev/null +++ b/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/outbound/MongoDbStoringMessageHandler.java @@ -0,0 +1,125 @@ +/* + * Copyright 2007-2012 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.springframework.data.mongodb.MongoDbFactory; +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.expression.Expression; +import org.springframework.expression.common.LiteralExpression; +import org.springframework.expression.spel.support.StandardEvaluationContext; +import org.springframework.integration.Message; +import org.springframework.integration.core.MessageHandler; +import org.springframework.integration.handler.AbstractMessageHandler; +import org.springframework.integration.util.ExpressionUtils; +import org.springframework.util.Assert; +/** + * Implementation of {@link MessageHandler} which writes Message payload into a MongoDb collection + * identified by evaluation of the {@link #collectionNameExpression}. + * + * @author Amol Nayak + * @author Oleg Zhurakousky + * @since 2.2 + * + */ +public class MongoDbStoringMessageHandler extends AbstractMessageHandler { + + private volatile MongoOperations mongoTemplate; + + private volatile MongoDbFactory mongoDbFactory; + + private volatile MongoConverter mongoConverter; + + private volatile StandardEvaluationContext evaluationContext; + + private volatile Expression collectionNameExpression = new LiteralExpression("data"); + + private volatile boolean initialized = false; + + /** + * Will construct this instance using provided {@link MongoDbFactory} + * + * @param mongoDbFactory + */ + public MongoDbStoringMessageHandler(MongoDbFactory mongoDbFactory){ + Assert.notNull(mongoDbFactory, "'mongoDbFactory' must not be null"); + + this.mongoDbFactory = mongoDbFactory; + } + + /** + * Will construct this instance using fully created and initialized instance of + * provided {@link MongoOperations} + * + * @param mongoTemplate + */ + public MongoDbStoringMessageHandler(MongoOperations mongoTemplate){ + Assert.notNull(mongoTemplate, "'mongoTemplate' must not be null"); + + this.mongoTemplate = mongoTemplate; + } + + /** + * Allows you to provide custom {@link MongoConverter} used to assist in serialization + * of data written to MongoDb. Only allowed if this instance was constructed with a + * {@link MongoDbFactory}. + * + * @param mongoConverter + */ + public void setMongoConverter(MongoConverter mongoConverter) { + Assert.isNull(this.mongoTemplate, + "'mongoConverter' can not be set when instance was constructed with MongoTemplate"); + this.mongoConverter = mongoConverter; + } + + /** + * Sets the SpEL {@link Expression} that should resolve to a collection name + * used by {@link MongoOperations} to store data + * + * @param collectionNameExpression + */ + public void setCollectionNameExpression(Expression collectionNameExpression) { + Assert.notNull(collectionNameExpression, "'collectionNameExpression' must not be null"); + this.collectionNameExpression = collectionNameExpression; + } + + @Override + protected void onInit() throws Exception { + if (this.getBeanFactory() != null) { + this.evaluationContext = + ExpressionUtils.createStandardEvaluationContext(this.getBeanFactory()); + } + else { + this.evaluationContext = ExpressionUtils.createStandardEvaluationContext(); + } + if (this.mongoTemplate == null){ + this.mongoTemplate = new MongoTemplate(this.mongoDbFactory, this.mongoConverter); + } + this.initialized = true; + } + + @Override + protected void handleMessageInternal(Message message) throws Exception { + Assert.isTrue(this.initialized, "This class is not yet initialized. Invoke its afterPropertiesSet() method"); + String collectionName = this.collectionNameExpression.getValue(this.evaluationContext, message, String.class); + Assert.notNull(collectionName, "'collectionNameExpression' must not evaluate to null"); + + Object payload = message.getPayload(); + + this.mongoTemplate.save(payload, collectionName); + } +} diff --git a/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/outbound/package-info.java b/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/outbound/package-info.java new file mode 100644 index 0000000000..76f94d97ab --- /dev/null +++ b/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/outbound/package-info.java @@ -0,0 +1,4 @@ +/** + * Provides classes related to the Mongo outbound channel adapters + */ +package org.springframework.integration.mongodb.outbound; \ No newline at end of file diff --git a/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/support/MongoHeaders.java b/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/support/MongoHeaders.java new file mode 100644 index 0000000000..19308dc82f --- /dev/null +++ b/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/support/MongoHeaders.java @@ -0,0 +1,16 @@ +package org.springframework.integration.mongodb.support; + +/** + * Pre-defined names and prefixes to be used for + * for dealing with headers required by Mongo components + * + * @author Gary Russell + * @since 2.2 + */ +public class MongoHeaders { + + public static final String PREFIX = "mongo_"; + + public static final String COLLECTION_NAME = PREFIX + "collectionName"; + +} diff --git a/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/support/package-info.java b/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/support/package-info.java new file mode 100644 index 0000000000..fa8441666b --- /dev/null +++ b/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/support/package-info.java @@ -0,0 +1,4 @@ +/** + * Provides supporting classes for this module. + */ +package org.springframework.integration.mongodb.support; \ No newline at end of file diff --git a/spring-integration-mongodb/src/main/resources/META-INF/spring.handlers b/spring-integration-mongodb/src/main/resources/META-INF/spring.handlers new file mode 100644 index 0000000000..2eeef28742 --- /dev/null +++ b/spring-integration-mongodb/src/main/resources/META-INF/spring.handlers @@ -0,0 +1 @@ +http\://www.springframework.org/schema/integration/mongodb=org.springframework.integration.mongodb.config.MongoDbNamespaceHandler \ No newline at end of file diff --git a/spring-integration-mongodb/src/main/resources/META-INF/spring.schemas b/spring-integration-mongodb/src/main/resources/META-INF/spring.schemas new file mode 100644 index 0000000000..ddab48351f --- /dev/null +++ b/spring-integration-mongodb/src/main/resources/META-INF/spring.schemas @@ -0,0 +1,2 @@ +http\://www.springframework.org/schema/integration/mongodb/spring-integration-mongodb-2.2.xsd=org/springframework/integration/mongodb/config/spring-integration-mongodb-2.2.xsd +http\://www.springframework.org/schema/integration/mongodb/spring-integration-mongodb.xsd=org/springframework/integration/mongodb/config/spring-integration-mongodb-2.2.xsd \ No newline at end of file diff --git a/spring-integration-mongodb/src/main/resources/META-INF/spring.tooling b/spring-integration-mongodb/src/main/resources/META-INF/spring.tooling new file mode 100644 index 0000000000..49bdf56465 --- /dev/null +++ b/spring-integration-mongodb/src/main/resources/META-INF/spring.tooling @@ -0,0 +1,4 @@ +# Tooling related information for the integration mongodb namespace +http\://www.springframework.org/schema/integration/mongodb@name=integration mongodb Namespace +http\://www.springframework.org/schema/integration/mongodb@prefix=int-mongodb +http\://www.springframework.org/schema/integration/mongodb@icon=org/springframework/integration/mongodb/config/spring-integration-mongodb.gif diff --git a/spring-integration-mongodb/src/main/resources/org/springframework/integration/mongodb/config/spring-integration-mongodb-2.2.xsd b/spring-integration-mongodb/src/main/resources/org/springframework/integration/mongodb/config/spring-integration-mongodb-2.2.xsd new file mode 100644 index 0000000000..bb359f1da9 --- /dev/null +++ b/spring-integration-mongodb/src/main/resources/org/springframework/integration/mongodb/config/spring-integration-mongodb-2.2.xsd @@ -0,0 +1,184 @@ + + + + + + + + + + + + + + Defines mongodb inbound channel adapter that + creates + + + + + + + + + + + + String representation of MongoDb Query (e.g., + query="{'name' : 'Bob'}"). + Please refer to MongoDb documentation for more query samples + http://www.mongodb.org/display/DOCS/Querying + This attribute is + mutually exclusive with 'query-expression' attribute. + + + + + + + SpEL expression which should resolve to a + String value identifying the + MongoDb Query. Also see 'query' attribute + This attribute is mutually exclusive with 'query' attribute. + + + + + + + + The fully qualified name of the entity class to be passed to + find(..) or findOne(..) method MongoTemplate. + If this attribute is not provided the default value is com.mongodb.DBObject + + + + + + + + + + + Allows you to manage find* method of MongoTemplate is used to query MongoDb. Default value for this + attribute is 'false'. This means that we'll use find(..) method thus resulting in a Message with + payload of type List of entities identified by 'entity-class' attribute. If you want/expect a single + value set this attribute to 'true' which will result in invocation of findOne(..) method resulting in + the payload of type identified by 'entity-class' attribute (default com.mongodb.DBObject) + + + + + + + + + + + + Defines mongodb outbound channel adapter that + writes the contents of the + Message into + org.springframework.data.mongodb.support.collections.mongodbStore + + + + + + + + + + + + + Common configuration for mongodb adapters. + + + + + + + Reference to a Message Channel that will be used + by this adapter to + 'receiveFrom' or 'sendTo' Messages depending on the adapter type (e.g., + inbound/outbound) + + + + + + + + + Reference to an instance of + org.springframework.data.mongodb.MongoDbFactory + + + + + + + + + + + + Reference to an instance of + org.springframework.data.mongodb.core.MongoTemplate + + + + + + + + + + Identifies the name of the MongoDb collection to + use. + This attribute is mutually exclusive with + 'collection-name-expression' + attribute. + + + + + + + SpEL expression which should resolve to a String + value identifying the + name of the MongoDb collection to use. + This + attribute is mutually exclusive with 'collection-name' attribute. + + + + + + + + + + + + Reference to an instance of + org.springframework.data.mongodb.core.convert.MongoConverter + + + + + + diff --git a/spring-integration-mongodb/src/main/resources/org/springframework/integration/mongodb/config/spring-integration-mongodb.gif b/spring-integration-mongodb/src/main/resources/org/springframework/integration/mongodb/config/spring-integration-mongodb.gif new file mode 100644 index 0000000000..351817f7b3 Binary files /dev/null and b/spring-integration-mongodb/src/main/resources/org/springframework/integration/mongodb/config/spring-integration-mongodb.gif differ diff --git a/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/MongoDbInboundChannelAdapterIntegrationTests.java b/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/MongoDbInboundChannelAdapterIntegrationTests.java new file mode 100644 index 0000000000..7fb3d045a8 --- /dev/null +++ b/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/MongoDbInboundChannelAdapterIntegrationTests.java @@ -0,0 +1,215 @@ +/* + * Copyright 2002-2012 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.config; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import java.util.List; + +import org.junit.Test; + +import org.springframework.beans.factory.parsing.BeanDefinitionParsingException; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.data.mongodb.MongoDbFactory; +import org.springframework.data.mongodb.core.MongoOperations; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.query.BasicQuery; +import org.springframework.integration.Message; +import org.springframework.integration.channel.QueueChannel; +import org.springframework.integration.endpoint.SourcePollingChannelAdapter; +import org.springframework.integration.mongodb.rules.MongoDbAvailable; +import org.springframework.integration.mongodb.rules.MongoDbAvailableTests; + +import com.mongodb.DBObject; +import com.mongodb.util.JSON; +/** + * @author Oleg Zhurakousky + * @since 2.2 + */ +public class MongoDbInboundChannelAdapterIntegrationTests extends MongoDbAvailableTests { + + @Test + @MongoDbAvailable + public void testWithDefaultMongoFactory() throws Exception{ + MongoDbFactory mongoDbFactory = this.prepareMongoFactory(); + MongoTemplate template = new MongoTemplate(mongoDbFactory); + template.save(this.createPerson("Bob"), "data"); + + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("inbound-adapter-config.xml", this.getClass()); + SourcePollingChannelAdapter spca = context.getBean("mongoInboundAdapter", SourcePollingChannelAdapter.class); + QueueChannel replyChannel = context.getBean("replyChannel", QueueChannel.class); + spca.start(); + + @SuppressWarnings("unchecked") + Message> message = (Message>) replyChannel.receive(1000); + assertNotNull(message); + assertEquals("Bob", message.getPayload().get(0).getName()); + assertNotNull(replyChannel.receive(1000)); + spca.stop(); + } + + @Test + @MongoDbAvailable + public void testWithNamedMongoFactory() throws Exception{ + MongoDbFactory mongoDbFactory = this.prepareMongoFactory(); + MongoTemplate template = new MongoTemplate(mongoDbFactory); + template.save(this.createPerson("Bob"), "data"); + + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("inbound-adapter-config.xml", this.getClass()); + SourcePollingChannelAdapter spca = context.getBean("mongoInboundAdapterNamedFactory", SourcePollingChannelAdapter.class); + QueueChannel replyChannel = context.getBean("replyChannel", QueueChannel.class); + spca.start(); + + @SuppressWarnings("unchecked") + Message> message = (Message>) replyChannel.receive(1000); + assertNotNull(message); + assertEquals("Bob", message.getPayload().get(0).get("name")); + spca.stop(); + } + + @Test + @MongoDbAvailable + public void testWithMongoTemplate() throws Exception{ + MongoDbFactory mongoDbFactory = this.prepareMongoFactory(); + MongoTemplate template = new MongoTemplate(mongoDbFactory); + template.save(this.createPerson("Bob"), "data"); + + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("inbound-adapter-config.xml", this.getClass()); + SourcePollingChannelAdapter spca = context.getBean("mongoInboundAdapterWithTemplate", SourcePollingChannelAdapter.class); + QueueChannel replyChannel = context.getBean("replyChannel", QueueChannel.class); + spca.start(); + + @SuppressWarnings("unchecked") + Message message = (Message) replyChannel.receive(1000); + assertNotNull(message); + assertEquals("Bob", message.getPayload().getName()); + spca.stop(); + } + + @Test + @MongoDbAvailable + public void testWithNamedCollection() throws Exception{ + MongoDbFactory mongoDbFactory = this.prepareMongoFactory(); + MongoTemplate template = new MongoTemplate(mongoDbFactory); + template.save(this.createPerson("Bob"), "foo"); + + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("inbound-adapter-config.xml", this.getClass()); + SourcePollingChannelAdapter spca = context.getBean("mongoInboundAdapterWithNamedCollection", SourcePollingChannelAdapter.class); + QueueChannel replyChannel = context.getBean("replyChannel", QueueChannel.class); + spca.start(); + + @SuppressWarnings("unchecked") + Message> message = (Message>) replyChannel.receive(1000); + assertNotNull(message); + assertEquals("Bob", message.getPayload().get(0).getName()); + spca.stop(); + } + + @Test + @MongoDbAvailable + public void testWithNamedCollectionExpression() throws Exception{ + MongoDbFactory mongoDbFactory = this.prepareMongoFactory(); + MongoTemplate template = new MongoTemplate(mongoDbFactory); + template.save(this.createPerson("Bob"), "foo"); + + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("inbound-adapter-config.xml", this.getClass()); + SourcePollingChannelAdapter spca = context.getBean("mongoInboundAdapterWithNamedCollectionExpression", SourcePollingChannelAdapter.class); + QueueChannel replyChannel = context.getBean("replyChannel", QueueChannel.class); + spca.start(); + + @SuppressWarnings("unchecked") + Message> message = (Message>) replyChannel.receive(1000); + assertNotNull(message); + assertEquals("Bob", message.getPayload().get(0).getName()); + spca.stop(); + } + + @Test + @MongoDbAvailable + public void testWithOnSuccessDisposition() throws Exception{ + MongoDbFactory mongoDbFactory = this.prepareMongoFactory(); + MongoTemplate template = new MongoTemplate(mongoDbFactory); + template.save(this.createPerson("Bob"), "data"); + + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("inbound-adapter-config.xml", this.getClass()); + SourcePollingChannelAdapter spca = context.getBean("inboundAdapterWithOnSuccessDisposition", SourcePollingChannelAdapter.class); + QueueChannel replyChannel = context.getBean("replyChannel", QueueChannel.class); + spca.start(); + + assertNotNull(replyChannel.receive(1000)); + Thread.sleep(300); + assertNull(replyChannel.receive(1000)); + spca.stop(); + } + + @Test + @MongoDbAvailable + public void testWithMongoConverter() throws Exception{ + MongoDbFactory mongoDbFactory = this.prepareMongoFactory(); + MongoTemplate template = new MongoTemplate(mongoDbFactory); + template.save(this.createPerson("Bob"), "data"); + + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("inbound-adapter-config.xml", this.getClass()); + SourcePollingChannelAdapter spca = context.getBean("mongoInboundAdapterWithConverter", SourcePollingChannelAdapter.class); + QueueChannel replyChannel = context.getBean("replyChannel", QueueChannel.class); + spca.start(); + + @SuppressWarnings("unchecked") + Message> message = (Message>) replyChannel.receive(1000); + assertNotNull(message); + assertEquals("Bob", message.getPayload().get(0).getName()); + assertNotNull(replyChannel.receive(1000)); + spca.stop(); + } + + @Test(expected=BeanDefinitionParsingException.class) + @MongoDbAvailable + public void testFailureWithQueryAndQueryExpression() throws Exception{ + new ClassPathXmlApplicationContext("inbound-fail-q-qex.xml", this.getClass()); + } + + @Test(expected=BeanDefinitionParsingException.class) + @MongoDbAvailable + public void testFailureWithFactoryAndTemplate() throws Exception{ + new ClassPathXmlApplicationContext("inbound-fail-factory-template.xml", this.getClass()); + } + + @Test(expected=BeanDefinitionParsingException.class) + @MongoDbAvailable + public void testFailureWithCollectionAndCollectioinExpression() throws Exception{ + new ClassPathXmlApplicationContext("inbound-fail-c-cex.xml", this.getClass()); + } + + @Test(expected=BeanDefinitionParsingException.class) + @MongoDbAvailable + public void testFailureWithTemplateAndConverter() throws Exception{ + new ClassPathXmlApplicationContext("inbound-fail-converter-template.xml", this.getClass()); + } + + public static class DocumentCleaner { + public void remove(MongoOperations mongoOperations, Object target, String collectionName) { + if (target instanceof List){ + List documents = (List) target; + for (Object document : documents) { + mongoOperations.remove(new BasicQuery(JSON.serialize(document)), collectionName); + } + } + } + } + +} diff --git a/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/MongoDbInboundChannelAdapterParserTests.java b/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/MongoDbInboundChannelAdapterParserTests.java new file mode 100644 index 0000000000..7e31fd8939 --- /dev/null +++ b/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/MongoDbInboundChannelAdapterParserTests.java @@ -0,0 +1,107 @@ +/* + * Copyright 2002-2012 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.config; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import org.springframework.beans.factory.parsing.BeanDefinitionParsingException; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.expression.common.LiteralExpression; +import org.springframework.expression.spel.standard.SpelExpression; +import org.springframework.integration.endpoint.SourcePollingChannelAdapter; +import org.springframework.integration.mongodb.inbound.MongoDbMessageSource; +import org.springframework.integration.test.util.TestUtils; +/** + * @author Oleg Zhurakousky + */ +public class MongoDbInboundChannelAdapterParserTests { + + @Test + public void minimalConfig(){ + ClassPathXmlApplicationContext context = + new ClassPathXmlApplicationContext("inbound-adapter-parser-config.xml", this.getClass()); + SourcePollingChannelAdapter spca = context.getBean("minimalConfig.adapter", SourcePollingChannelAdapter.class); + MongoDbMessageSource source = TestUtils.getPropertyValue(spca, "source", MongoDbMessageSource.class); + + assertEquals(false, TestUtils.getPropertyValue(spca, "shouldTrack")); + assertNotNull(TestUtils.getPropertyValue(source, "mongoTemplate")); + assertEquals(context.getBean("mongoDbFactory"), TestUtils.getPropertyValue(source, "mongoDbFactory")); + assertNotNull(TestUtils.getPropertyValue(source, "evaluationContext")); + assertTrue(TestUtils.getPropertyValue(source, "collectionNameExpression") instanceof LiteralExpression); + assertEquals("data", TestUtils.getPropertyValue(source, "collectionNameExpression.literalValue")); + } + + @Test + public void fullConfigWithCollectionExpression(){ + ClassPathXmlApplicationContext context = + new ClassPathXmlApplicationContext("inbound-adapter-parser-config.xml", this.getClass()); + SourcePollingChannelAdapter spca = context.getBean("fullConfigWithCollectionExpression.adapter", SourcePollingChannelAdapter.class); + MongoDbMessageSource source = TestUtils.getPropertyValue(spca, "source", MongoDbMessageSource.class); + + assertEquals(false, TestUtils.getPropertyValue(spca, "shouldTrack")); + assertNotNull(TestUtils.getPropertyValue(source, "mongoTemplate")); + assertEquals(context.getBean("mongoDbFactory"), TestUtils.getPropertyValue(source, "mongoDbFactory")); + assertEquals(context.getBean("mongoConverter"), TestUtils.getPropertyValue(source, "mongoConverter")); + assertNotNull(TestUtils.getPropertyValue(source, "evaluationContext")); + assertTrue(TestUtils.getPropertyValue(source, "collectionNameExpression") instanceof SpelExpression); + assertEquals("'foo'", TestUtils.getPropertyValue(source, "collectionNameExpression.expression")); + } + + @Test + public void fullConfigWithCollectionName(){ + ClassPathXmlApplicationContext context = + new ClassPathXmlApplicationContext("inbound-adapter-parser-config.xml", this.getClass()); + SourcePollingChannelAdapter spca = context.getBean("fullConfigWithCollectionName.adapter", SourcePollingChannelAdapter.class); + MongoDbMessageSource source = TestUtils.getPropertyValue(spca, "source", MongoDbMessageSource.class); + + assertEquals(false, TestUtils.getPropertyValue(spca, "shouldTrack")); + assertNotNull(TestUtils.getPropertyValue(source, "mongoTemplate")); + assertEquals(context.getBean("mongoDbFactory"), TestUtils.getPropertyValue(source, "mongoDbFactory")); + assertEquals(context.getBean("mongoConverter"), TestUtils.getPropertyValue(source, "mongoConverter")); + assertNotNull(TestUtils.getPropertyValue(source, "evaluationContext")); + assertTrue(TestUtils.getPropertyValue(source, "collectionNameExpression") instanceof LiteralExpression); + assertEquals("foo", TestUtils.getPropertyValue(source, "collectionNameExpression.literalValue")); + } + + @Test + public void fullConfigWithMongoTemplate(){ + ClassPathXmlApplicationContext context = + new ClassPathXmlApplicationContext("inbound-adapter-parser-config.xml", this.getClass()); + SourcePollingChannelAdapter spca = context.getBean("fullConfigWithMongoTemplate.adapter", SourcePollingChannelAdapter.class); + MongoDbMessageSource source = TestUtils.getPropertyValue(spca, "source", MongoDbMessageSource.class); + + assertEquals(false, TestUtils.getPropertyValue(spca, "shouldTrack")); + assertNotNull(TestUtils.getPropertyValue(source, "mongoTemplate")); + assertEquals(context.getBean("mongoDbTemplate"), TestUtils.getPropertyValue(source, "mongoTemplate")); + assertNotNull(TestUtils.getPropertyValue(source, "evaluationContext")); + assertTrue(TestUtils.getPropertyValue(source, "collectionNameExpression") instanceof LiteralExpression); + assertEquals("foo", TestUtils.getPropertyValue(source, "collectionNameExpression.literalValue")); + } + + @Test(expected=BeanDefinitionParsingException.class) + public void templateAndFactoryFail(){ + new ClassPathXmlApplicationContext("inbound-adapter-parser-fail-template-factory-config.xml", this.getClass()); + } + + @Test(expected=BeanDefinitionParsingException.class) + public void templateAndConverterFail(){ + new ClassPathXmlApplicationContext("inbound-adapter-parser-fail-template-converter-config.xml", this.getClass()); + } +} diff --git a/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/MongoDbOutboundChannelAdapterIntegrationTests.java b/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/MongoDbOutboundChannelAdapterIntegrationTests.java new file mode 100644 index 0000000000..37f8d1f059 --- /dev/null +++ b/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/MongoDbOutboundChannelAdapterIntegrationTests.java @@ -0,0 +1,112 @@ +/* + * Copyright 2002-2012 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.config; + +import static org.junit.Assert.assertNotNull; + +import org.junit.Test; + +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.data.mongodb.MongoDbFactory; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.query.BasicQuery; +import org.springframework.integration.Message; +import org.springframework.integration.MessageChannel; +import org.springframework.integration.message.GenericMessage; +import org.springframework.integration.mongodb.rules.MongoDbAvailable; +import org.springframework.integration.mongodb.rules.MongoDbAvailableTests; +import org.springframework.integration.support.MessageBuilder; + +import com.mongodb.BasicDBObject; +import com.mongodb.util.JSON; +/** + * @author Oleg Zhurakousky + */ +public class MongoDbOutboundChannelAdapterIntegrationTests extends MongoDbAvailableTests { + + @Test + @MongoDbAvailable + public void testWithDefaultMongoFactory() throws Exception{ + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("outbound-adapter-config.xml", this.getClass()); + + MessageChannel channel = context.getBean("simpleAdapter", MessageChannel.class); + Message message = new GenericMessage(this.createPerson("Bob")); + channel.send(message); + + MongoDbFactory mongoDbFactory = this.prepareMongoFactory(); + MongoTemplate template = new MongoTemplate(mongoDbFactory); + assertNotNull(template.find(new BasicQuery("{'name' : 'Bob'}"), Person.class, "data")); + } + + @Test + @MongoDbAvailable + public void testWithNamedCollection() throws Exception{ + MongoDbFactory mongoDbFactory = this.prepareMongoFactory("foo"); + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("outbound-adapter-config.xml", this.getClass()); + + MessageChannel channel = context.getBean("simpleAdapterWithNamedCollection", MessageChannel.class); + Message message = MessageBuilder.withPayload(this.createPerson("Bob")).setHeader("collectionName", "foo").build(); + channel.send(message); + + MongoTemplate template = new MongoTemplate(mongoDbFactory); + assertNotNull(template.find(new BasicQuery("{'name' : 'Bob'}"), Person.class, "foo")); + } + + @Test + @MongoDbAvailable + public void testWithTemplate() throws Exception{ + MongoDbFactory mongoDbFactory = this.prepareMongoFactory("foo"); + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("outbound-adapter-config.xml", this.getClass()); + + MessageChannel channel = context.getBean("simpleAdapterWithTemplate", MessageChannel.class); + Message message = MessageBuilder.withPayload(this.createPerson("Bob")).setHeader("collectionName", "foo").build(); + channel.send(message); + + MongoTemplate template = new MongoTemplate(mongoDbFactory); + assertNotNull(template.find(new BasicQuery("{'name' : 'Bob'}"), Person.class, "foo")); + } + + @Test + @MongoDbAvailable + public void testSavingDbObject() throws Exception{ + + BasicDBObject dbObject = (BasicDBObject) JSON.parse("{'foo' : 'bar'}"); + + MongoDbFactory mongoDbFactory = this.prepareMongoFactory("foo"); + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("outbound-adapter-config.xml", this.getClass()); + + MessageChannel channel = context.getBean("simpleAdapterWithTemplate", MessageChannel.class); + Message message = MessageBuilder.withPayload(dbObject).setHeader("collectionName", "foo").build(); + channel.send(message); + + MongoTemplate template = new MongoTemplate(mongoDbFactory); + assertNotNull(template.find(new BasicQuery("{'foo' : 'bar'}"), BasicDBObject.class, "foo")); + } + + @Test + @MongoDbAvailable + public void testWithMongoConverter() throws Exception{ + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("outbound-adapter-config.xml", this.getClass()); + + MessageChannel channel = context.getBean("simpleAdapterWithConverter", MessageChannel.class); + Message message = new GenericMessage(this.createPerson("Bob")); + channel.send(message); + + MongoDbFactory mongoDbFactory = this.prepareMongoFactory(); + MongoTemplate template = new MongoTemplate(mongoDbFactory); + assertNotNull(template.find(new BasicQuery("{'name' : 'Bob'}"), Person.class, "data")); + } +} diff --git a/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/MongoDbOutboundChannelAdapterParserTests.java b/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/MongoDbOutboundChannelAdapterParserTests.java new file mode 100644 index 0000000000..dd4d14ccd1 --- /dev/null +++ b/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/MongoDbOutboundChannelAdapterParserTests.java @@ -0,0 +1,103 @@ +/* + * Copyright 2002-2012 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.config; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import org.springframework.beans.factory.parsing.BeanDefinitionParsingException; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.expression.common.LiteralExpression; +import org.springframework.expression.spel.standard.SpelExpression; +import org.springframework.integration.mongodb.outbound.MongoDbStoringMessageHandler; +import org.springframework.integration.test.util.TestUtils; +/** + * @author Oleg Zhurakousky + */ +public class MongoDbOutboundChannelAdapterParserTests { + + @Test + public void minimalConfig(){ + ClassPathXmlApplicationContext context = + new ClassPathXmlApplicationContext("outbound-adapter-parser-config.xml", this.getClass()); + MongoDbStoringMessageHandler handler = + TestUtils.getPropertyValue(context.getBean("minimalConfig.adapter"), "handler", MongoDbStoringMessageHandler.class); + assertEquals("minimalConfig.adapter", TestUtils.getPropertyValue(handler, "componentName")); + assertEquals(false, TestUtils.getPropertyValue(handler, "shouldTrack")); + assertNotNull(TestUtils.getPropertyValue(handler, "mongoTemplate")); + assertEquals(context.getBean("mongoDbFactory"), TestUtils.getPropertyValue(handler, "mongoDbFactory")); + assertNotNull(TestUtils.getPropertyValue(handler, "evaluationContext")); + assertTrue(TestUtils.getPropertyValue(handler, "collectionNameExpression") instanceof LiteralExpression); + assertEquals("data", TestUtils.getPropertyValue(handler, "collectionNameExpression.literalValue")); + } + + @Test + public void fullConfigWithCollectionExpression(){ + ClassPathXmlApplicationContext context = + new ClassPathXmlApplicationContext("outbound-adapter-parser-config.xml", this.getClass()); + MongoDbStoringMessageHandler handler = + TestUtils.getPropertyValue(context.getBean("fullConfigWithCollectionExpression.adapter"), "handler", MongoDbStoringMessageHandler.class); + assertEquals("fullConfigWithCollectionExpression.adapter", TestUtils.getPropertyValue(handler, "componentName")); + assertEquals(false, TestUtils.getPropertyValue(handler, "shouldTrack")); + assertNotNull(TestUtils.getPropertyValue(handler, "mongoTemplate")); + assertEquals(context.getBean("mongoDbFactory"), TestUtils.getPropertyValue(handler, "mongoDbFactory")); + assertNotNull(TestUtils.getPropertyValue(handler, "evaluationContext")); + assertTrue(TestUtils.getPropertyValue(handler, "collectionNameExpression") instanceof SpelExpression); + assertEquals("headers.collectionName", TestUtils.getPropertyValue(handler, "collectionNameExpression.expression")); + } + + @Test + public void fullConfigWithCollection(){ + ClassPathXmlApplicationContext context = + new ClassPathXmlApplicationContext("outbound-adapter-parser-config.xml", this.getClass()); + MongoDbStoringMessageHandler handler = + TestUtils.getPropertyValue(context.getBean("fullConfigWithCollection.adapter"), "handler", MongoDbStoringMessageHandler.class); + assertEquals("fullConfigWithCollection.adapter", TestUtils.getPropertyValue(handler, "componentName")); + assertEquals(false, TestUtils.getPropertyValue(handler, "shouldTrack")); + assertNotNull(TestUtils.getPropertyValue(handler, "mongoTemplate")); + assertEquals(context.getBean("mongoDbFactory"), TestUtils.getPropertyValue(handler, "mongoDbFactory")); + assertNotNull(TestUtils.getPropertyValue(handler, "evaluationContext")); + assertTrue(TestUtils.getPropertyValue(handler, "collectionNameExpression") instanceof LiteralExpression); + assertEquals("foo", TestUtils.getPropertyValue(handler, "collectionNameExpression.literalValue")); + } + + @Test + public void fullConfigWithMongoTemplate(){ + ClassPathXmlApplicationContext context = + new ClassPathXmlApplicationContext("outbound-adapter-parser-config.xml", this.getClass()); + MongoDbStoringMessageHandler handler = + TestUtils.getPropertyValue(context.getBean("fullConfigWithMongoTemplate.adapter"), "handler", MongoDbStoringMessageHandler.class); + assertEquals("fullConfigWithMongoTemplate.adapter", TestUtils.getPropertyValue(handler, "componentName")); + assertEquals(false, TestUtils.getPropertyValue(handler, "shouldTrack")); + assertNotNull(TestUtils.getPropertyValue(handler, "mongoTemplate")); + assertNotNull(TestUtils.getPropertyValue(handler, "evaluationContext")); + assertTrue(TestUtils.getPropertyValue(handler, "collectionNameExpression") instanceof LiteralExpression); + assertEquals("foo", TestUtils.getPropertyValue(handler, "collectionNameExpression.literalValue")); + } + + @Test(expected=BeanDefinitionParsingException.class) + public void templateAndFactoryFail(){ + new ClassPathXmlApplicationContext("outbound-adapter-parser-fail-template-factory-config.xml", this.getClass()); + } + + @Test(expected=BeanDefinitionParsingException.class) + public void templateAndConverterFail(){ + new ClassPathXmlApplicationContext("outbound-adapter-parser-fail-template-converter-config.xml", this.getClass()); + } +} diff --git a/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/inbound-adapter-config.xml b/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/inbound-adapter-config.xml new file mode 100644 index 0000000000..5d6cd19452 --- /dev/null +++ b/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/inbound-adapter-config.xml @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/inbound-adapter-parser-config.xml b/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/inbound-adapter-parser-config.xml new file mode 100644 index 0000000000..8f9235e9d4 --- /dev/null +++ b/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/inbound-adapter-parser-config.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/inbound-adapter-parser-fail-template-converter-config.xml b/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/inbound-adapter-parser-fail-template-converter-config.xml new file mode 100644 index 0000000000..ddf64fc161 --- /dev/null +++ b/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/inbound-adapter-parser-fail-template-converter-config.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/inbound-adapter-parser-fail-template-factory-config.xml b/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/inbound-adapter-parser-fail-template-factory-config.xml new file mode 100644 index 0000000000..e6cbdc205f --- /dev/null +++ b/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/inbound-adapter-parser-fail-template-factory-config.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + diff --git a/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/inbound-fail-c-cex.xml b/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/inbound-fail-c-cex.xml new file mode 100644 index 0000000000..58253861d6 --- /dev/null +++ b/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/inbound-fail-c-cex.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + diff --git a/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/inbound-fail-converter-template.xml b/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/inbound-fail-converter-template.xml new file mode 100644 index 0000000000..0f8e8c3e5a --- /dev/null +++ b/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/inbound-fail-converter-template.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/inbound-fail-factory-template.xml b/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/inbound-fail-factory-template.xml new file mode 100644 index 0000000000..b6f45f0790 --- /dev/null +++ b/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/inbound-fail-factory-template.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + diff --git a/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/inbound-fail-q-qex.xml b/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/inbound-fail-q-qex.xml new file mode 100644 index 0000000000..925f277440 --- /dev/null +++ b/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/inbound-fail-q-qex.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + diff --git a/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/outbound-adapter-config.xml b/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/outbound-adapter-config.xml new file mode 100644 index 0000000000..11f2bf4c2c --- /dev/null +++ b/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/outbound-adapter-config.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/outbound-adapter-parser-config.xml b/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/outbound-adapter-parser-config.xml new file mode 100644 index 0000000000..033665318f --- /dev/null +++ b/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/outbound-adapter-parser-config.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/outbound-adapter-parser-fail-template-converter-config.xml b/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/outbound-adapter-parser-fail-template-converter-config.xml new file mode 100644 index 0000000000..92da91477a --- /dev/null +++ b/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/outbound-adapter-parser-fail-template-converter-config.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/outbound-adapter-parser-fail-template-factory-config.xml b/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/outbound-adapter-parser-fail-template-factory-config.xml new file mode 100644 index 0000000000..1e23827597 --- /dev/null +++ b/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/config/outbound-adapter-parser-fail-template-factory-config.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + diff --git a/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/inbound/MongoDbMessageSourceTests.java b/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/inbound/MongoDbMessageSourceTests.java new file mode 100644 index 0000000000..cdb71b8aa2 --- /dev/null +++ b/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/inbound/MongoDbMessageSourceTests.java @@ -0,0 +1,261 @@ +/* + * Copyright 2007-2012 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.inbound; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import java.util.List; + +import org.junit.Test; +import org.mockito.Mockito; +import org.springframework.data.mongodb.MongoDbFactory; +import org.springframework.data.mongodb.core.MongoOperations; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.convert.MappingMongoConverter; +import org.springframework.data.mongodb.core.mapping.MongoMappingContext; +import org.springframework.expression.Expression; +import org.springframework.expression.common.LiteralExpression; +import org.springframework.integration.mongodb.rules.MongoDbAvailable; +import org.springframework.integration.mongodb.rules.MongoDbAvailableTests; + +import com.mongodb.DBObject; +import com.mongodb.util.JSON; + +/** + * @author Amol Nayak + * @author Oleg Zhurakousky + * + * @since 2.2 + * + */ +public class MongoDbMessageSourceTests extends MongoDbAvailableTests { + /** + * Tests by providing a null MongoDB Factory + * + */ + @Test(expected=IllegalArgumentException.class) + public void withNullMongoDBFactory() { + Expression expression = mock(Expression.class); + new MongoDbMessageSource((MongoDbFactory)null, expression); + } + + @Test(expected=IllegalArgumentException.class) + public void withNullMongoTemplate() { + Expression expression = mock(Expression.class); + new MongoDbMessageSource((MongoOperations)null, expression); + } + + @Test(expected=IllegalArgumentException.class) + public void withNullQueryExpression() { + MongoDbFactory mongoDbFactory = mock(MongoDbFactory.class); + new MongoDbMessageSource(mongoDbFactory, null); + } + + @Test + @MongoDbAvailable + public void validateSuccessfullQueryWithSinigleElementIfOneInListAsDbObject() throws Exception { + + MongoDbFactory mongoDbFactory = this.prepareMongoFactory(); + + MongoTemplate template = new MongoTemplate(mongoDbFactory); + template.save(this.createPerson(), "data"); + + Expression queryExpression = new LiteralExpression("{'name' : 'Oleg'}"); + MongoDbMessageSource messageSource = new MongoDbMessageSource(mongoDbFactory, queryExpression); + messageSource.afterPropertiesSet(); + @SuppressWarnings("unchecked") + List results = ((List)messageSource.receive().getPayload()); + assertEquals(1, results.size()); + DBObject resultObject = results.get(0); + + assertEquals("Oleg", resultObject.get("name")); + } + + @Test + @MongoDbAvailable + public void validateSuccessfullQueryWithSinigleElementIfOneInList() throws Exception { + + MongoDbFactory mongoDbFactory = this.prepareMongoFactory(); + + MongoTemplate template = new MongoTemplate(mongoDbFactory); + template.save(this.createPerson(), "data"); + + Expression queryExpression = new LiteralExpression("{'name' : 'Oleg'}"); + MongoDbMessageSource messageSource = new MongoDbMessageSource(mongoDbFactory, queryExpression); + messageSource.setEntityClass(Object.class); + messageSource.afterPropertiesSet(); + @SuppressWarnings("unchecked") + List results = ((List)messageSource.receive().getPayload()); + assertEquals(1, results.size()); + Person person = results.get(0); + assertEquals("Oleg", person.getName()); + assertEquals("PA", person.getAddress().getState()); + } + + @Test + @MongoDbAvailable + public void validateSuccessfullQueryWithSinigleElementIfOneInListAndSingleResult() throws Exception { + + MongoDbFactory mongoDbFactory = this.prepareMongoFactory(); + + MongoTemplate template = new MongoTemplate(mongoDbFactory); + template.save(this.createPerson(), "data"); + + Expression queryExpression = new LiteralExpression("{'name' : 'Oleg'}"); + MongoDbMessageSource messageSource = new MongoDbMessageSource(mongoDbFactory, queryExpression); + messageSource.setEntityClass(Object.class); + messageSource.setExpectSingleResult(true); + messageSource.afterPropertiesSet(); + Person person = (Person)messageSource.receive().getPayload(); + + assertEquals("Oleg", person.getName()); + assertEquals("PA", person.getAddress().getState()); + } + + + @Test + @MongoDbAvailable + public void validateSuccessfullSubObjectQueryWithSinigleElementIfOneInList() throws Exception { + + MongoDbFactory mongoDbFactory = this.prepareMongoFactory(); + + MongoTemplate template = new MongoTemplate(mongoDbFactory); + template.save(this.createPerson(), "data"); + + Expression queryExpression = new LiteralExpression("{'address.state' : 'PA'}"); + MongoDbMessageSource messageSource = new MongoDbMessageSource(mongoDbFactory, queryExpression); + messageSource.setEntityClass(Object.class); + messageSource.afterPropertiesSet(); + @SuppressWarnings("unchecked") + List results = ((List)messageSource.receive().getPayload()); + Person person = results.get(0); + assertEquals("Oleg", person.getName()); + assertEquals("PA", person.getAddress().getState()); + } + + @Test + @MongoDbAvailable + public void validateSuccessfullQueryWithMultipleElements() throws Exception { + + MongoDbFactory mongoDbFactory = this.prepareMongoFactory(); + + MongoTemplate template = new MongoTemplate(mongoDbFactory); + template.save(this.createPerson("Manny"), "data"); + template.save(this.createPerson("Moe"), "data"); + template.save(this.createPerson("Jack"), "data"); + + Expression queryExpression = new LiteralExpression("{'address.state' : 'PA'}"); + MongoDbMessageSource messageSource = new MongoDbMessageSource(mongoDbFactory, queryExpression); + messageSource.afterPropertiesSet(); + @SuppressWarnings("unchecked") + List persons = (List) messageSource.receive().getPayload(); + assertEquals(3, persons.size()); + } + + @Test + @MongoDbAvailable + public void validateSuccessfullQueryWithNullReturn() throws Exception { + + MongoDbFactory mongoDbFactory = this.prepareMongoFactory(); + + MongoTemplate template = new MongoTemplate(mongoDbFactory); + template.save(this.createPerson("Manny"), "data"); + template.save(this.createPerson("Moe"), "data"); + template.save(this.createPerson("Jack"), "data"); + + Expression queryExpression = new LiteralExpression("{'address.state' : 'NJ'}"); + MongoDbMessageSource messageSource = new MongoDbMessageSource(mongoDbFactory, queryExpression); + messageSource.afterPropertiesSet(); + assertNull(messageSource.receive()); + } + + @SuppressWarnings("unchecked") + @Test + @MongoDbAvailable + public void validateSuccessfullQueryWithCustomConverter() throws Exception { + + MongoDbFactory mongoDbFactory = this.prepareMongoFactory(); + + MongoTemplate template = new MongoTemplate(mongoDbFactory); + template.save(this.createPerson("Manny"), "data"); + template.save(this.createPerson("Moe"), "data"); + template.save(this.createPerson("Jack"), "data"); + + Expression queryExpression = new LiteralExpression("{'address.state' : 'PA'}"); + MongoDbMessageSource messageSource = new MongoDbMessageSource(mongoDbFactory, queryExpression); + MappingMongoConverter converter = new TestMongoConverter(mongoDbFactory, new MongoMappingContext()); + converter.afterPropertiesSet(); + converter = spy(converter); + messageSource.setMongoConverter(converter); + messageSource.afterPropertiesSet(); + + List persons = (List) messageSource.receive().getPayload(); + assertEquals(3, persons.size()); + verify(converter, times(3)).read((Class) Mockito.any(), Mockito.any(DBObject.class)); + } + + @SuppressWarnings("unchecked") + @Test + @MongoDbAvailable + public void validateSuccessfullQueryWithMongoTemplate() throws Exception { + + MongoDbFactory mongoDbFactory = this.prepareMongoFactory(); + + MappingMongoConverter converter = new TestMongoConverter(mongoDbFactory, new MongoMappingContext()); + converter.afterPropertiesSet(); + converter = spy(converter); + + MongoTemplate template = new MongoTemplate(mongoDbFactory, converter); + Expression queryExpression = new LiteralExpression("{'address.state' : 'PA'}"); + MongoDbMessageSource messageSource = new MongoDbMessageSource(template, queryExpression); + messageSource.afterPropertiesSet(); + + MongoTemplate writingTemplate = new MongoTemplate(mongoDbFactory, converter); + writingTemplate.save(this.createPerson("Manny"), "data"); + writingTemplate.save(this.createPerson("Moe"), "data"); + writingTemplate.save(this.createPerson("Jack"), "data"); + + List persons = (List) messageSource.receive().getPayload(); + assertEquals(3, persons.size()); + verify(converter, times(3)).read((Class) Mockito.any(), Mockito.any(DBObject.class)); + } + + @Test + @MongoDbAvailable + public void validatePipelineInModifyOut() throws Exception { + + MongoDbFactory mongoDbFactory = this.prepareMongoFactory(); + + MongoTemplate template = new MongoTemplate(mongoDbFactory); + template.save(JSON.parse("{'name' : 'Manny', 'id' : 1}"), "data"); + + Expression queryExpression = new LiteralExpression("{'name' : 'Manny'}"); + MongoDbMessageSource messageSource = new MongoDbMessageSource(mongoDbFactory, queryExpression); + messageSource.setExpectSingleResult(true); + messageSource.afterPropertiesSet(); + DBObject result = (DBObject) messageSource.receive().getPayload(); + Object id = result.get("_id"); + result.put("company","PepBoys"); + template.save(result, "data"); + result = (DBObject) messageSource.receive().getPayload(); + assertEquals(id, result.get("_id")); + } +} diff --git a/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/outbound/MongoDbStoringMessageHandlerTests.java b/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/outbound/MongoDbStoringMessageHandlerTests.java new file mode 100644 index 0000000000..b564cafc82 --- /dev/null +++ b/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/outbound/MongoDbStoringMessageHandlerTests.java @@ -0,0 +1,145 @@ +/* + * Copyright 2007-2012 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 static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import org.junit.Test; +import org.mockito.Mockito; + +import org.springframework.data.mongodb.MongoDbFactory; +import org.springframework.data.mongodb.core.MongoOperations; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.convert.MappingMongoConverter; +import org.springframework.data.mongodb.core.mapping.MongoMappingContext; +import org.springframework.data.mongodb.core.query.BasicQuery; +import org.springframework.data.mongodb.core.query.Query; +import org.springframework.expression.common.LiteralExpression; +import org.springframework.integration.Message; +import org.springframework.integration.mongodb.rules.MongoDbAvailable; +import org.springframework.integration.mongodb.rules.MongoDbAvailableTests; +import org.springframework.integration.support.MessageBuilder; + +import com.mongodb.DBObject; + +/** + * @author Amol Nayak + * @author Oleg Zhurakousky + * + * @since 2.2 + */ +public class MongoDbStoringMessageHandlerTests extends MongoDbAvailableTests { + + @Test(expected=IllegalArgumentException.class) + public void withNullMongoDBFactory() { + new MongoDbStoringMessageHandler((MongoDbFactory)null); + } + + @Test(expected=IllegalArgumentException.class) + public void withNullMongoTemplate() { + new MongoDbStoringMessageHandler((MongoOperations)null); + } + + + @Test + @MongoDbAvailable + public void validateMessageHandlingWithDefaultCollection() throws Exception { + + MongoDbFactory mongoDbFactory = this.prepareMongoFactory(); + MongoDbStoringMessageHandler handler = new MongoDbStoringMessageHandler(mongoDbFactory); + handler.afterPropertiesSet(); + Message message = MessageBuilder.withPayload(this.createPerson("Bob")).build(); + handler.handleMessage(message); + + MongoTemplate template = new MongoTemplate(mongoDbFactory); + Query query = new BasicQuery("{'name' : 'Bob'}"); + Person person = template.findOne(query, Person.class, "data"); + + assertEquals("Bob", person.getName()); + assertEquals("PA", person.getAddress().getState()); + } + + @Test + @MongoDbAvailable + public void validateMessageHandlingWithNamedCollection() throws Exception { + + MongoDbFactory mongoDbFactory = this.prepareMongoFactory(); + MongoDbStoringMessageHandler handler = new MongoDbStoringMessageHandler(mongoDbFactory); + handler.setCollectionNameExpression(new LiteralExpression("foo")); + handler.afterPropertiesSet(); + Message message = MessageBuilder.withPayload(this.createPerson("Bob")).build(); + handler.handleMessage(message); + + MongoTemplate template = new MongoTemplate(mongoDbFactory); + Query query = new BasicQuery("{'name' : 'Bob'}"); + Person person = template.findOne(query, Person.class, "foo"); + + assertEquals("Bob", person.getName()); + assertEquals("PA", person.getAddress().getState()); + } + + @Test + @MongoDbAvailable + public void validateMessageHandlingWithMongoConverter() throws Exception { + + MongoDbFactory mongoDbFactory = this.prepareMongoFactory(); + MongoDbStoringMessageHandler handler = new MongoDbStoringMessageHandler(mongoDbFactory); + handler.setCollectionNameExpression(new LiteralExpression("foo")); + MappingMongoConverter converter = new TestMongoConverter(mongoDbFactory, new MongoMappingContext()); + converter.afterPropertiesSet(); + converter = spy(converter); + handler.setMongoConverter(converter); + handler.afterPropertiesSet(); + Message message = MessageBuilder.withPayload(this.createPerson("Bob")).build(); + handler.handleMessage(message); + + MongoTemplate template = new MongoTemplate(mongoDbFactory); + Query query = new BasicQuery("{'name' : 'Bob'}"); + Person person = template.findOne(query, Person.class, "foo"); + + assertEquals("Bob", person.getName()); + assertEquals("PA", person.getAddress().getState()); + verify(converter, times(1)).write(Mockito.any(), Mockito.any(DBObject.class)); + } + + @Test + @MongoDbAvailable + public void validateMessageHandlingWithMongoTemplate() throws Exception { + MongoDbFactory mongoDbFactory = this.prepareMongoFactory(); + MappingMongoConverter converter = new TestMongoConverter(mongoDbFactory, new MongoMappingContext()); + converter.afterPropertiesSet(); + converter = spy(converter); + MongoTemplate template = new MongoTemplate(mongoDbFactory, converter); + + + MongoDbStoringMessageHandler handler = new MongoDbStoringMessageHandler(template); + handler.setCollectionNameExpression(new LiteralExpression("foo")); + handler.afterPropertiesSet(); + Message message = MessageBuilder.withPayload(this.createPerson("Bob")).build(); + handler.handleMessage(message); + + MongoTemplate readingTemplate = new MongoTemplate(mongoDbFactory); + Query query = new BasicQuery("{'name' : 'Bob'}"); + Person person = readingTemplate.findOne(query, Person.class, "foo"); + + assertEquals("Bob", person.getName()); + assertEquals("PA", person.getAddress().getState()); + verify(converter, times(1)).write(Mockito.any(), Mockito.any(DBObject.class)); + } +} 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 1cd6cf2aea..3b2bdbb9ee 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 @@ -17,15 +17,21 @@ package org.springframework.integration.mongodb.rules; import org.junit.Rule; + +import org.springframework.data.mapping.context.MappingContext; import org.springframework.data.mongodb.MongoDbFactory; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.SimpleMongoDbFactory; +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 com.mongodb.DBObject; import com.mongodb.Mongo; /** * Convenience base class that enables unit test methods to rely upon the {@link MongoDbAvailable} annotation. - * + * * @author Oleg Zhurakousky * @since 2.1 */ @@ -33,13 +39,101 @@ public abstract class MongoDbAvailableTests { @Rule public MongoDbAvailableRule redisAvailableRule = new MongoDbAvailableRule(); - - - protected MongoDbFactory prepareMongoFactory() throws Exception{ + + + protected MongoDbFactory prepareMongoFactory(String... additionalCollectionToDrop) throws Exception{ MongoDbFactory mongoDbFactory = new SimpleMongoDbFactory(new Mongo(), "test"); MongoTemplate template = new MongoTemplate(mongoDbFactory); template.dropCollection("messages"); + template.dropCollection("data"); + for (String additionalCollection : additionalCollectionToDrop) { + template.dropCollection(additionalCollection); + } return mongoDbFactory; } + public Person createPerson(){ + Address address = new Address(); + address.setCity("Philadelphia"); + address.setStreet("2121 Rawn street"); + address.setState("PA"); + + Person person = new Person(); + person.setAddress(address); + person.setName("Oleg"); + return person; + } + + public Person createPerson(String name){ + Address address = new Address(); + address.setCity("Philadelphia"); + address.setStreet("2121 Rawn street"); + address.setState("PA"); + + Person person = new Person(); + person.setAddress(address); + person.setName(name); + return person; + } + + public static class Person { + private Address address; + private String name; + public Address getAddress() { + return address; + } + public void setAddress(Address address) { + this.address = address; + } + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + } + + public static class Address { + private String street; + private String city; + private String state; + public String getStreet() { + return street; + } + public void setStreet(String street) { + this.street = street; + } + public String getCity() { + return city; + } + public void setCity(String city) { + this.city = city; + } + public String getState() { + return state; + } + public void setState(String state) { + this.state = state; + } + } + + public static class TestMongoConverter extends MappingMongoConverter { + + public TestMongoConverter( + MongoDbFactory mongoDbFactory, + MappingContext, MongoPersistentProperty> mappingContext) { + super(mongoDbFactory, mappingContext); + } + + @Override + public void write(Object source, DBObject target) { + super.write(source, target); + } + + @Override + public S read(Class clazz, DBObject source) { + return super.read(clazz, source); + } + } + }