From c26a1c6c6bad9da92d581e77a91c4320ea56be99 Mon Sep 17 00:00:00 2001 From: Oleg Zhurakousky Date: Tue, 26 Jul 2011 08:47:35 -0400 Subject: [PATCH] INT-1991 moved MongoDB module to the main branch --- build.gradle | 12 ++ pom.xml | 2 + settings.gradle | 1 + spring-integration-mongodb/pom.xml | 173 +++++++++++++++ .../mongodb/store/MongoMessageStore.java | 197 ++++++++++++++++++ .../MongoClaimCheckIntegrationTests.java | 145 +++++++++++++ .../mongodb/store/MongoMessageStoreTests.java | 44 ++++ spring-integration-mongodb/template.mf | 17 ++ 8 files changed, 591 insertions(+) create mode 100644 spring-integration-mongodb/pom.xml create mode 100644 spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/store/MongoMessageStore.java create mode 100644 spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/store/MongoClaimCheckIntegrationTests.java create mode 100644 spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/store/MongoMessageStoreTests.java create mode 100644 spring-integration-mongodb/template.mf diff --git a/build.gradle b/build.gradle index b96f3d642a..f3dedf0f3e 100644 --- a/build.gradle +++ b/build.gradle @@ -123,6 +123,8 @@ configure(javaprojects) { mockitoVersion = '1.8.4' springVersion = '3.1.0.M2' springAmqpVersion = '1.0.0.RC2' + springDataMongoVersion = '1.0.0.BUILD-SNAPSHOT' + springDataCommonsVersion = '1.2.0.BUILD-SNAPSHOT' springSecurityVersion = '3.0.5.RELEASE' springWsVersion = '2.0.2.RELEASE' @@ -321,6 +323,16 @@ project('spring-integration-mail') { [compileJava,compileTestJava]*.options*.compilerArgs = ["${xLintArg},-path"] } +project('spring-integration-mongodb') { + description = 'Spring Integration MongoDB Support' + dependencies { + compile project(":spring-integration-core") + compile "org.springframework:spring-context:$springVersion" + compile "org.springframework.data:spring-data-mongodb:$springDataMongoVersion" + compile "org.springframework.data:spring-data-commons-core:$springDataCommonsVersion" + } +} + project('spring-integration-rmi') { description = 'Spring Integration RMI Support' dependencies { diff --git a/pom.xml b/pom.xml index d01ae7a0a8..5b6833e553 100644 --- a/pom.xml +++ b/pom.xml @@ -8,6 +8,7 @@ pom Spring Integration + spring-integration-amqp spring-integration-core spring-integration-event spring-integration-feed @@ -20,6 +21,7 @@ spring-integration-jms spring-integration-jmx spring-integration-mail + spring-integration-mongodb spring-integration-rmi spring-integration-security spring-integration-sftp diff --git a/settings.gradle b/settings.gradle index b45d2f2a24..8138a6daab 100644 --- a/settings.gradle +++ b/settings.gradle @@ -30,6 +30,7 @@ include 'spring-integration-jdbc' include 'spring-integration-jms' include 'spring-integration-jmx' include 'spring-integration-mail' +include 'spring-integration-mongodb' include 'spring-integration-rmi' include 'spring-integration-security' include 'spring-integration-sftp' diff --git a/spring-integration-mongodb/pom.xml b/spring-integration-mongodb/pom.xml new file mode 100644 index 0000000000..f4dd74208a --- /dev/null +++ b/spring-integration-mongodb/pom.xml @@ -0,0 +1,173 @@ + + + 4.0.0 + org.springframework.integration + spring-integration-mongodb + 2.1.0.BUILD-SNAPSHOT + Spring Integration MongoDB Support + + + The Apache Software License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + + + + src/main/java + + **/* + + + **/*.java + + + + src/main/resources + + **/* + + + + + + src/test/java + + **/* + + + **/*.java + + + + src/test/resources + + **/* + + + + + + maven-compiler-plugin + + 1.5 + 1.5 + + + + maven-surefire-plugin + + + **/*Tests.java + + + **/*Abstract*.java + + + + + + + + http://download.java.net/maven/2 + http://download.java.net/maven/2 + + + http://maven.springframework.org/milestone + http://maven.springframework.org/milestone + + + http://maven.springframework.org/release + http://maven.springframework.org/release + + + http://maven.springframework.org/snapshot + http://maven.springframework.org/snapshot + + + http://repository.springsource.com/maven/bundles/external + http://repository.springsource.com/maven/bundles/external + + + http://repository.springsource.com/maven/bundles/milestone + http://repository.springsource.com/maven/bundles/milestone + + + http://repository.springsource.com/maven/bundles/release + http://repository.springsource.com/maven/bundles/release + + + + + org.easymock + easymock + 2.3 + test + + + org.easymock + easymockclassextension + 2.3 + test + + + org.springframework + spring-test + 3.1.0.M2 + test + + + org.springframework.data + spring-data-mongodb + 1.0.0.BUILD-SNAPSHOT + compile + + + org.springframework.integration + spring-integration-core + 2.1.0.BUILD-SNAPSHOT + compile + + + org.springframework + spring-context + 3.1.0.M2 + compile + + + org.hamcrest + hamcrest-all + 1.1 + test + + + org.mockito + mockito-all + 1.8.4 + test + + + log4j + log4j + 1.2.12 + test + + + cglib + cglib-nodep + 2.2 + test + + + junit + junit-dep + 4.8.2 + test + + + + UTF8 + + diff --git a/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/store/MongoMessageStore.java b/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/store/MongoMessageStore.java new file mode 100644 index 0000000000..952f6b3472 --- /dev/null +++ b/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/store/MongoMessageStore.java @@ -0,0 +1,197 @@ +/* + * Copyright 2002-2011 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.store; + +import static org.springframework.data.mongodb.core.query.Criteria.where; + +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + +import org.bson.types.ObjectId; +import org.springframework.beans.DirectFieldAccessor; +import org.springframework.beans.factory.BeanClassLoaderAware; +import org.springframework.core.convert.converter.Converter; +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.convert.MongoConverter; +import org.springframework.data.mongodb.core.mapping.MongoMappingContext; +import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity; +import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty; +import org.springframework.data.mongodb.core.query.Query; +import org.springframework.integration.Message; +import org.springframework.integration.MessageHeaders; +import org.springframework.integration.message.GenericMessage; +import org.springframework.integration.store.MessageStore; +import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; + +import com.mongodb.DBObject; +import com.mongodb.Mongo; + +/** + * @author Mark Fisher + * @author Oleg Zhurakousky + */ +public class MongoMessageStore implements MessageStore, BeanClassLoaderAware { + + private final static String DEFAULT_COLLECTION_NAME = "messages"; + + private final MongoTemplate template; + + //private final MongoConverter mongoConverter = new MessageReadingMongoConverter(); + private final MongoConverter mongoConverter = null; + + private volatile ClassLoader classLoader = ClassUtils.getDefaultClassLoader(); + + + public MongoMessageStore(Mongo mongo, String databaseName) { + Assert.notNull(mongo, "mongo must not be null"); + Assert.hasText(databaseName, "databaseName must not be empty"); + MongoDbFactory mongoFactory = new SimpleMongoDbFactory(mongo, databaseName); + MessageReadingMongoConverter converter = new MessageReadingMongoConverter(mongoFactory, new MongoMappingContext()); + this.template = new MongoTemplate(mongoFactory, converter); +// this.template.setDefaultCollectionName(DEFAULT_COLLECTION_NAME); +// this.template.createCollection(DEFAULT_COLLECTION_NAME); + } + + + public void setCollectionName(String collectionName) { + Assert.hasText(collectionName, "collectionName must not be empty"); + //this.template.setDefaultCollectionName(collectionName); + this.template.createCollection(collectionName); + } + +// public void setUsername(String username) { +// template.setUsername(username); +// } +// +// public void setPassword(String password) { +// template.setPassword(password); +// } + + public void setBeanClassLoader(ClassLoader classLoader) { + Assert.notNull(classLoader, "classLoader must not be null"); + this.classLoader = classLoader; + } + + public Message addMessage(Message message) { + this.template.insert(message, "messages"); + return message; + } + + public Message getMessage(UUID id) { + return this.template.findOne(this.idQuery(id), Message.class); + } + + public int getMessageCount() { + // TODO: long to int + return new Long(this.template.getCollection(DEFAULT_COLLECTION_NAME).getCount()).intValue(); + } + + public Message removeMessage(UUID id) { + return this.template.findAndRemove(idQuery(id), Message.class, "messages"); + } + + private Query idQuery(UUID id) { + System.out.println(id.toString()); + return new Query(where("_id").is(id.toString())); + } + + + private class MessageReadingMongoConverter extends MappingMongoConverter { + + public MessageReadingMongoConverter( + MongoDbFactory mongoDbFactory, + MappingContext, MongoPersistentProperty> mappingContext) { + super(mongoDbFactory, mappingContext); + // TODO Auto-generated constructor stub + } + + + @Override + public void afterPropertiesSet() { + super.afterPropertiesSet(); + Set> customConverters = new HashSet>(); + customConverters.add(new UuidToStringConverter()); + customConverters.add(new StringToUuidConverter()); + //this.setCustomConverters(customConverters); + } + + + @Override + public void write(Object source, DBObject target) { + if (source instanceof Message) { + String payloadType = ((Message) source).getPayload().getClass().getName(); + target.put("_payloadType", payloadType); + target.put("_id", ((Message) source).getHeaders().getId().toString()); + } + +// // TODO: fix this (the base class should handle it via converters?) +// if (source instanceof UUID) { +// target.put("uuid", ((UUID)source).toString()); +// } + super.write(source, target); + } + + + @Override + @SuppressWarnings({"unchecked", "rawtypes"}) + public S read(Class clazz, DBObject source) { + if (!Message.class.equals(clazz)) { + return super.read(clazz, source); + } + Map headers = (Map) source.get("headers"); + Object payload = source.get("payload"); + Object payloadType = source.get("_payloadType"); + if (payloadType != null && payload instanceof DBObject) { + try { + Class payloadClass = ClassUtils.forName(payloadType.toString(), classLoader); + payload = this.read(payloadClass, (DBObject) payload); + } + catch (Exception e) { + throw new IllegalStateException("failed to load class: " + payloadType, e); + } + } + GenericMessage message = new GenericMessage(payload, headers); + Map innerMap = (Map) new DirectFieldAccessor(message.getHeaders()).getPropertyValue("headers"); + // TODO: unpick this mess + innerMap.put(MessageHeaders.ID, UUID.fromString(source.get("_id").toString())); + innerMap.put(MessageHeaders.TIMESTAMP, headers.get(MessageHeaders.TIMESTAMP)); + return (S) message; + } + } + + + private static class UuidToStringConverter implements Converter { + public String convert(UUID source) { + return source.toString(); + } + } + + + private static class StringToUuidConverter implements Converter { + public UUID convert(String source) { + return UUID.fromString(source); + } + } + +} diff --git a/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/store/MongoClaimCheckIntegrationTests.java b/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/store/MongoClaimCheckIntegrationTests.java new file mode 100644 index 0000000000..1cc6e74bf2 --- /dev/null +++ b/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/store/MongoClaimCheckIntegrationTests.java @@ -0,0 +1,145 @@ +/* + * Copyright 2002-2011 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.store; + +import static org.junit.Assert.assertEquals; + +import org.junit.Ignore; +import org.junit.Test; + +import org.springframework.integration.Message; +import org.springframework.integration.support.MessageBuilder; +import org.springframework.integration.transformer.ClaimCheckInTransformer; +import org.springframework.integration.transformer.ClaimCheckOutTransformer; + +import com.mongodb.Mongo; + +/** + * @author Mark Fisher + */ +public class MongoClaimCheckIntegrationTests { + + @Test @Ignore + public void stringPayload() throws Exception { + Mongo mongo = new Mongo(); + MongoMessageStore messageStore = new MongoMessageStore(mongo, "test"); + ClaimCheckInTransformer checkin = new ClaimCheckInTransformer(messageStore); + ClaimCheckOutTransformer checkout = new ClaimCheckOutTransformer(messageStore); + Message originalMessage = MessageBuilder.withPayload("test1").build(); + Message claimCheckMessage = checkin.transform(originalMessage); + assertEquals(originalMessage.getHeaders().getId(), claimCheckMessage.getPayload()); + Message checkedOutMessage = checkout.transform(claimCheckMessage); + assertEquals(claimCheckMessage.getPayload(), checkedOutMessage.getHeaders().getId()); + assertEquals(originalMessage.getPayload(), checkedOutMessage.getPayload()); + assertEquals(originalMessage, checkedOutMessage); + //System.out.println("original: " + originalMessage); + //System.out.println("claimcheck: " + claimCheckMessage); + //System.out.println("checkedout: " + checkedOutMessage); + } + + @Test @Ignore + public void objectPayload() throws Exception { + Mongo mongo = new Mongo(); + MongoMessageStore messageStore = new MongoMessageStore(mongo, "test"); + ClaimCheckInTransformer checkin = new ClaimCheckInTransformer(messageStore); + ClaimCheckOutTransformer checkout = new ClaimCheckOutTransformer(messageStore); + Beverage payload = new Beverage(); + payload.setName("latte"); + payload.setShots(3); + payload.setIced(false); + Message originalMessage = MessageBuilder.withPayload(payload).build(); + Message claimCheckMessage = checkin.transform(originalMessage); + assertEquals(originalMessage.getHeaders().getId(), claimCheckMessage.getPayload()); + Message checkedOutMessage = checkout.transform(claimCheckMessage); + assertEquals(originalMessage.getPayload(), checkedOutMessage.getPayload()); + assertEquals(claimCheckMessage.getPayload(), checkedOutMessage.getHeaders().getId()); + assertEquals(originalMessage, checkedOutMessage); + } + + + @SuppressWarnings("unused") + private static class Beverage { + + private String name; + private int shots; + private boolean iced; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getShots() { + return shots; + } + + public void setShots(int shots) { + this.shots = shots; + } + + public boolean isIced() { + return iced; + } + + public void setIced(boolean iced) { + this.iced = iced; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (iced ? 1231 : 1237); + result = prime * result + ((name == null) ? 0 : name.hashCode()); + result = prime * result + shots; + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + Beverage other = (Beverage) obj; + if (iced != other.iced) { + return false; + } + if (name == null) { + if (other.name != null) { + return false; + } + } + else if (!name.equals(other.name)) { + return false; + } + if (shots != other.shots) { + return false; + } + return true; + } + } + +} diff --git a/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/store/MongoMessageStoreTests.java b/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/store/MongoMessageStoreTests.java new file mode 100644 index 0000000000..5c434075c4 --- /dev/null +++ b/spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/store/MongoMessageStoreTests.java @@ -0,0 +1,44 @@ +/* + * Copyright 2002-2011 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.store; + +import org.junit.Ignore; +import org.junit.Test; + +import org.springframework.integration.Message; +import org.springframework.integration.support.MessageBuilder; + +import com.mongodb.Mongo; + +/** + * @author Mark Fisher + */ +public class MongoMessageStoreTests { + + @Test @Ignore + public void addAndRemove() throws Exception { + Mongo mongo = new Mongo(); + MongoMessageStore store = new MongoMessageStore(mongo, "test"); + Message message = MessageBuilder.withPayload("UUID again and again").build(); + Message claimCheck = store.addMessage(message); + System.out.println("added: " + claimCheck); + //Thread.sleep(10000); + message = store.removeMessage(message.getHeaders().getId()); + System.out.println("removed: " + message); + } + +} diff --git a/spring-integration-mongodb/template.mf b/spring-integration-mongodb/template.mf new file mode 100644 index 0000000000..a40a9053e4 --- /dev/null +++ b/spring-integration-mongodb/template.mf @@ -0,0 +1,17 @@ +Bundle-SymbolicName: org.springframework.integration.mongodb +Bundle-Name: Spring Integration MongoDB Support +Bundle-Vendor: SpringSource +Bundle-ManifestVersion: 2 +Import-Template: + org.apache.commons.logging;version="[1.1.1, 2.0.0)", + org.springframework.integration.*;version="[2.0.0, 2.0.1)", + org.springframework.beans.*;version="[3.0.0, 4.0.0)", + org.springframework.context;version="[3.0.0, 4.0.0)", + org.springframework.core.*;version="[3.0.0, 4.0.0)", + org.springframework.expression.*;version="[3.0.0, 4.0.0)", + org.springframework.util;version="[3.0.0, 4.0.0)", + org.springframework.expression.*;version="[3.0.0, 4.0.0)", + org.springframework.data.document.mongodb.*;version="[1.0.0, 2.0.0)", + com.mongodb.*;version="[2.4.0, 2.5.0]", + javax.*;version="0", + org.w3c.dom.*;version="0"