diff --git a/build.gradle b/build.gradle
index 21bc5fa4cb..ed263f4008 100644
--- a/build.gradle
+++ b/build.gradle
@@ -458,6 +458,7 @@ project('spring-integration-mongodb') {
exclude group: 'org.springframework', module: 'spring-expression'
exclude group: 'org.springframework', module: 'spring-tx'
}
+ testCompile "org.slf4j:slf4j-log4j12:$slf4jVersion"
}
}
diff --git a/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/metadata/MongoDbMetadataStore.java b/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/metadata/MongoDbMetadataStore.java
new file mode 100644
index 0000000000..26517bd43c
--- /dev/null
+++ b/spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/metadata/MongoDbMetadataStore.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright 2015 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.metadata;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.springframework.dao.DataAccessException;
+import org.springframework.data.mongodb.MongoDbFactory;
+import org.springframework.data.mongodb.core.CollectionCallback;
+import org.springframework.data.mongodb.core.MongoTemplate;
+import org.springframework.data.mongodb.core.ScriptOperations;
+import org.springframework.data.mongodb.core.query.Criteria;
+import org.springframework.data.mongodb.core.query.Query;
+import org.springframework.data.mongodb.core.query.Update;
+import org.springframework.data.mongodb.core.script.NamedMongoScript;
+import org.springframework.integration.metadata.ConcurrentMetadataStore;
+import org.springframework.util.Assert;
+
+import com.mongodb.BasicDBObject;
+import com.mongodb.DBCollection;
+import com.mongodb.MongoException;
+
+/**
+ * MongoDbMetadataStore implementation of {@link ConcurrentMetadataStore}.
+ * Use this {@link org.springframework.integration.metadata.MetadataStore} to
+ * achieve meta-data persistence shared across application instances and
+ * restarts.
+ *
+ * @author Senthil Arumugam, Samiraj Panneer Selvam
+ * @author Artem Bilan
+ * @since 4.2
+ *
+ */
+public class MongoDbMetadataStore implements ConcurrentMetadataStore {
+
+ private static final String DEFAULT_COLLECTION_NAME = "metadataStore";
+
+ private static final String ID_FIELD = "_id";
+
+ private static final String VALUE = "value";
+
+ private static final String PUT_IF_ABSENT_FUNCTION =
+ "function putIfAbsent(collection, key, value){ " +
+ " var alreadyPresent = db[collection].findOne({\"_id\": key}, {\"_id\": 0}); " +
+ " if(alreadyPresent == null){" +
+ " db[collection].insert({\"_id\": key, \"value\": value}); " +
+ " return null; " +
+ " }" +
+ " return alreadyPresent;" +
+ "}";
+
+ private static final String PUT_IF_ABSENT_SCRIPT_NAME = "metadataStorePutIfAbsent";
+
+ private final MongoTemplate template;
+
+ private final String collectionName;
+
+ private final ScriptOperations scriptOperations;
+
+ private volatile boolean scriptInitialized;
+
+ /**
+ * Configure the MongoDbMetadataStore by provided {@link MongoDbFactory} and
+ * default collection name - {@link #DEFAULT_COLLECTION_NAME}.
+ * @param factory the mongodb factory
+ */
+ public MongoDbMetadataStore(MongoDbFactory factory) {
+ this(factory, DEFAULT_COLLECTION_NAME);
+ }
+
+ /**
+ * Configure the MongoDbMetadataStore by provided {@link MongoDbFactory} and
+ * collection name
+ * @param factory the mongodb factory
+ * @param collectionName the collection name where it persists the data
+ */
+ public MongoDbMetadataStore(MongoDbFactory factory, String collectionName) {
+ this(new MongoTemplate(factory), collectionName);
+ }
+
+ /**
+ * Configure the MongoDbMetadataStore by provided {@link MongoTemplate} and
+ * default collection name - {@link #DEFAULT_COLLECTION_NAME}.
+ * @param template the mongodb template
+ */
+ public MongoDbMetadataStore(MongoTemplate template) {
+ this(template, DEFAULT_COLLECTION_NAME);
+ }
+
+ /**
+ * Configure the MongoDbMetadataStore by provided {@link MongoTemplate} and collection name.
+ * @param template the mongodb template
+ * @param collectionName the collection name where it persists the data
+ */
+ public MongoDbMetadataStore(MongoTemplate template, String collectionName) {
+ Assert.notNull(template, "'template' must not be null.");
+ Assert.hasText(collectionName, "'collectionName' must not be empty.");
+ this.template = template;
+ this.collectionName = collectionName;
+ this.scriptOperations = template.scriptOps();
+ }
+
+ /**
+ * Store a metadata {@code value} under provided {@code key} to the configured
+ * {@link #collectionName}.
+ *
+ * If a document does not exist with the specified {@code key}, the method performs an {@code insert}.
+ * If a document exists with the specified {@code key}, the method performs an {@code update}.
+ * @param key the metadata entry key
+ * @param value the metadata entry value
+ * @see MongoTemplate#execute(String, CollectionCallback)
+ * @see DBCollection#save
+ */
+ @Override
+ public void put(String key, String value) {
+ Assert.hasText(key, "'key' must not be empty.");
+ Assert.hasText(value, "'value' must not be empty.");
+ final Map entry = new HashMap();
+ entry.put(ID_FIELD, key);
+ entry.put(VALUE, value);
+ this.template.execute(this.collectionName, (CollectionCallback