diff --git a/pom.xml b/pom.xml
index d5c7aaf0c4..c8ce08fa9d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
org.springframework.dataspring-data-mongodb-parent
- 1.7.0.BUILD-SNAPSHOT
+ 1.7.0.DATAMONGO-1158-SNAPSHOTpomSpring Data MongoDB
diff --git a/spring-data-mongodb-cross-store/pom.xml b/spring-data-mongodb-cross-store/pom.xml
index c7610beee4..4f241a3e6f 100644
--- a/spring-data-mongodb-cross-store/pom.xml
+++ b/spring-data-mongodb-cross-store/pom.xml
@@ -6,7 +6,7 @@
org.springframework.dataspring-data-mongodb-parent
- 1.7.0.BUILD-SNAPSHOT
+ 1.7.0.DATAMONGO-1158-SNAPSHOT../pom.xml
@@ -48,7 +48,7 @@
org.springframework.dataspring-data-mongodb
- 1.7.0.BUILD-SNAPSHOT
+ 1.7.0.DATAMONGO-1158-SNAPSHOT
diff --git a/spring-data-mongodb-distribution/pom.xml b/spring-data-mongodb-distribution/pom.xml
index 13110137b6..c7cd8fafee 100644
--- a/spring-data-mongodb-distribution/pom.xml
+++ b/spring-data-mongodb-distribution/pom.xml
@@ -13,7 +13,7 @@
org.springframework.dataspring-data-mongodb-parent
- 1.7.0.BUILD-SNAPSHOT
+ 1.7.0.DATAMONGO-1158-SNAPSHOT../pom.xml
diff --git a/spring-data-mongodb-log4j/pom.xml b/spring-data-mongodb-log4j/pom.xml
index 6ff09e4577..7f18bc490b 100644
--- a/spring-data-mongodb-log4j/pom.xml
+++ b/spring-data-mongodb-log4j/pom.xml
@@ -5,7 +5,7 @@
org.springframework.dataspring-data-mongodb-parent
- 1.7.0.BUILD-SNAPSHOT
+ 1.7.0.DATAMONGO-1158-SNAPSHOT../pom.xml
diff --git a/spring-data-mongodb/pom.xml b/spring-data-mongodb/pom.xml
index 7c2d818c42..e0ce636323 100644
--- a/spring-data-mongodb/pom.xml
+++ b/spring-data-mongodb/pom.xml
@@ -11,7 +11,7 @@
org.springframework.dataspring-data-mongodb-parent
- 1.7.0.BUILD-SNAPSHOT
+ 1.7.0.DATAMONGO-1158-SNAPSHOT../pom.xml
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoClientVersion.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoClientVersion.java
new file mode 100644
index 0000000000..f8c8f1a8a5
--- /dev/null
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoClientVersion.java
@@ -0,0 +1,47 @@
+/*
+ * 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.data.mongodb;
+
+import org.springframework.util.ClassUtils;
+
+/**
+ * {@link MongoClientVersion} holds information about the used mongo-java client and is used to distinguish between
+ * different versions.
+ *
+ * @author Christoph Strobl
+ * @since 1.7
+ */
+public class MongoClientVersion {
+
+ private static final boolean IS_MONGO_30 = ClassUtils.isPresent("com.mongodb.binding.SingleServerBinding",
+ MongoClientVersion.class.getClassLoader());
+ private static final boolean IS_ASYNC_CLIENT = ClassUtils.isPresent("com.mongodb.async.client.MongoClient",
+ MongoClientVersion.class.getClassLoader());
+
+ /**
+ * @return true if mongo-java-driver version 3 or later is on classpath.
+ */
+ public static boolean isMongo3Driver() {
+ return IS_MONGO_30;
+ }
+
+ /**
+ * @return true if mongodb-driver-async is on classpath.
+ */
+ public static boolean isAsyncClient() {
+ return IS_ASYNC_CLIENT;
+ }
+}
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/AbstractMongoConfiguration.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/AbstractMongoConfiguration.java
index dc2776d723..b3915c7530 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/AbstractMongoConfiguration.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/AbstractMongoConfiguration.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2014 the original author or authors.
+ * Copyright 2011-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.
@@ -46,6 +46,7 @@
import org.springframework.util.StringUtils;
import com.mongodb.Mongo;
+import com.mongodb.MongoClient;
/**
* Base class for Spring Data MongoDB configuration using JavaConfig.
@@ -54,6 +55,7 @@
* @author Oliver Gierke
* @author Thomas Darimont
* @author Ryan Tenney
+ * @author Christoph Strobl
*/
@Configuration
public abstract class AbstractMongoConfiguration {
@@ -70,7 +72,10 @@ public abstract class AbstractMongoConfiguration {
* returned by {@link #getDatabaseName()} later on effectively.
*
* @return
+ * @deprecated since 1.7. {@link MongoClient} should hold authentication data within
+ * {@link MongoClient#getCredentialsList()}
*/
+ @Deprecated
protected String getAuthenticationDatabaseName() {
return null;
}
@@ -129,7 +134,10 @@ protected String getMappingBasePackage() {
* be used.
*
* @return
+ * @deprecated since 1.7. {@link MongoClient} should hold authentication data within
+ * {@link MongoClient#getCredentialsList()}
*/
+ @Deprecated
protected UserCredentials getUserCredentials() {
return null;
}
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoClientParser.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoClientParser.java
new file mode 100644
index 0000000000..94159c1836
--- /dev/null
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoClientParser.java
@@ -0,0 +1,86 @@
+/*
+ * 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.data.mongodb.config;
+
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.parsing.BeanComponentDefinition;
+import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.xml.BeanDefinitionParser;
+import org.springframework.beans.factory.xml.ParserContext;
+import org.springframework.data.config.BeanComponentDefinitionBuilder;
+import org.springframework.data.config.ParsingUtils;
+import org.springframework.data.mongodb.core.MongoClientFactoryBean;
+import org.springframework.util.StringUtils;
+import org.w3c.dom.Element;
+
+/**
+ * Parser for {@code mongo-client} definitions.
+ *
+ * @author Christoph Strobl
+ * @since 1.7
+ */
+public class MongoClientParser implements BeanDefinitionParser {
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.beans.factory.xml.BeanDefinitionParser#parse(org.w3c.dom.Element, org.springframework.beans.factory.xml.ParserContext)
+ */
+ public BeanDefinition parse(Element element, ParserContext parserContext) {
+
+ Object source = parserContext.extractSource(element);
+ String id = element.getAttribute("id");
+
+ BeanComponentDefinitionBuilder helper = new BeanComponentDefinitionBuilder(element, parserContext);
+
+ BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MongoClientFactoryBean.class);
+
+ ParsingUtils.setPropertyValue(builder, element, "port", "port");
+ ParsingUtils.setPropertyValue(builder, element, "host", "host");
+ ParsingUtils.setPropertyValue(builder, element, "credentials", "credentials");
+
+ MongoParsingUtils.parseMongoClientOptions(element, builder);
+ MongoParsingUtils.parseReplicaSet(element, builder);
+
+ String defaultedId = StringUtils.hasText(id) ? id : BeanNames.MONGO_BEAN_NAME;
+
+ parserContext.pushContainingComponent(new CompositeComponentDefinition("Mongo", source));
+
+ BeanComponentDefinition mongoComponent = helper.getComponent(builder, defaultedId);
+ parserContext.registerBeanComponent(mongoComponent);
+
+ BeanComponentDefinition serverAddressPropertyEditor = helper.getComponent(MongoParsingUtils
+ .getServerAddressPropertyEditorBuilder());
+ parserContext.registerBeanComponent(serverAddressPropertyEditor);
+
+ BeanComponentDefinition writeConcernEditor = helper.getComponent(MongoParsingUtils
+ .getWriteConcernPropertyEditorBuilder());
+ parserContext.registerBeanComponent(writeConcernEditor);
+
+ BeanComponentDefinition readPreferenceEditor = helper.getComponent(MongoParsingUtils
+ .getReadPreferencePropertyEditorBuilder());
+ parserContext.registerBeanComponent(readPreferenceEditor);
+
+ BeanComponentDefinition credentialsEditor = helper.getComponent(MongoParsingUtils
+ .getMongoCredentialPropertyEditor());
+ parserContext.registerBeanComponent(credentialsEditor);
+
+ parserContext.popAndRegisterContainingComponent();
+
+ return mongoComponent.getBeanDefinition();
+ }
+
+}
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoCredentialPropertyEditor.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoCredentialPropertyEditor.java
new file mode 100644
index 0000000000..f90a5f5766
--- /dev/null
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoCredentialPropertyEditor.java
@@ -0,0 +1,124 @@
+/*
+ * 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.data.mongodb.config;
+
+import java.beans.PropertyEditorSupport;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import org.springframework.util.StringUtils;
+
+import com.mongodb.MongoCredential;
+
+/**
+ * Parse a {@link String} to a Collection of {@link MongoCredential}.
+ *
+ * @author Christoph Strobl
+ * @since 1.7
+ */
+public class MongoCredentialPropertyEditor extends PropertyEditorSupport {
+
+ private static final String AUTH_MECHANISM_KEY = "uri.authMechanism";
+ private static final String USERNAME_PASSWORD_DELIMINATOR = ":";
+ private static final String DATABASE_DELIMINATOR = "@";
+ private static final String OPTIONS_DELIMINATOR = "?";
+ private static final String OPTION_VALUE_DELIMINATOR = "&";
+
+ @Override
+ public void setAsText(String text) throws IllegalArgumentException {
+
+ if (!StringUtils.hasText(text)) {
+ return;
+ }
+
+ List credentials = new ArrayList();
+ for (String credentialString : text.split(",")) {
+
+ if (!text.contains(USERNAME_PASSWORD_DELIMINATOR) || !text.contains(DATABASE_DELIMINATOR)) {
+ throw new IllegalArgumentException("Credentials need to be in format 'username:password@database'!");
+ }
+
+ String[] userNameAndPassword = extractUserNameAndPassword(credentialString);
+ String database = extractDB(credentialString);
+ Properties options = extractOptions(credentialString);
+
+ if (!options.isEmpty()) {
+ if (options.containsKey(AUTH_MECHANISM_KEY)) {
+ String authMechanism = options.getProperty(AUTH_MECHANISM_KEY);
+ if (MongoCredential.GSSAPI_MECHANISM.equals(authMechanism)) {
+ credentials.add(MongoCredential.createGSSAPICredential(userNameAndPassword[0]));
+ } else if (MongoCredential.MONGODB_CR_MECHANISM.equals(authMechanism)) {
+ credentials.add(MongoCredential.createMongoCRCredential(userNameAndPassword[0], database,
+ userNameAndPassword[1].toCharArray()));
+ } else if (MongoCredential.MONGODB_X509_MECHANISM.equals(authMechanism)) {
+ credentials.add(MongoCredential.createMongoX509Credential(userNameAndPassword[0]));
+ } else if (MongoCredential.PLAIN_MECHANISM.equals(authMechanism)) {
+ credentials.add(MongoCredential.createPlainCredential(userNameAndPassword[0], database,
+ userNameAndPassword[1].toCharArray()));
+ } else if (MongoCredential.SCRAM_SHA_1_MECHANISM.equals(authMechanism)) {
+ credentials.add(MongoCredential.createScramSha1Credential(userNameAndPassword[0], database,
+ userNameAndPassword[1].toCharArray()));
+ } else {
+ throw new IllegalArgumentException(String.format(
+ "Cannot create MongoCredentials for unknown auth mechanism '%s'!", authMechanism));
+ }
+ }
+ } else {
+ credentials.add(MongoCredential.createCredential(userNameAndPassword[0], database,
+ userNameAndPassword[1].toCharArray()));
+ }
+ }
+
+ setValue(credentials);
+ }
+
+ private String[] extractUserNameAndPassword(String text) {
+
+ int dbSeperationIndex = text.lastIndexOf(DATABASE_DELIMINATOR);
+ String userNameAndPassword = text.substring(0, dbSeperationIndex);
+ return userNameAndPassword.split(USERNAME_PASSWORD_DELIMINATOR);
+ }
+
+ private String extractDB(String text) {
+
+ int dbSeperationIndex = text.lastIndexOf(DATABASE_DELIMINATOR);
+
+ String tmp = text.substring(dbSeperationIndex + 1);
+ int optionsSeperationIndex = tmp.lastIndexOf(OPTIONS_DELIMINATOR);
+
+ return optionsSeperationIndex > -1 ? tmp.substring(0, optionsSeperationIndex) : tmp;
+ }
+
+ private Properties extractOptions(String text) {
+
+ int optionsSeperationIndex = text.lastIndexOf(OPTIONS_DELIMINATOR);
+ int dbSeperationIndex = text.lastIndexOf(OPTIONS_DELIMINATOR);
+
+ if (optionsSeperationIndex == -1 || dbSeperationIndex > optionsSeperationIndex) {
+ return new Properties();
+ }
+
+ Properties properties = new Properties();
+
+ for (String option : text.substring(optionsSeperationIndex + 1).split(OPTION_VALUE_DELIMINATOR)) {
+ String[] optionArgs = option.split("=");
+ properties.put(optionArgs[0], optionArgs[1]);
+ }
+
+ return properties;
+ }
+}
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoNamespaceHandler.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoNamespaceHandler.java
index 89b6c2f843..377eedb446 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoNamespaceHandler.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoNamespaceHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2014 the original author or authors.
+ * Copyright 2011-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.
@@ -22,6 +22,7 @@
*
* @author Oliver Gierke
* @author Martin Baumgartner
+ * @author Christoph Strobl
*/
public class MongoNamespaceHandler extends NamespaceHandlerSupport {
@@ -33,6 +34,7 @@ public void init() {
registerBeanDefinitionParser("mapping-converter", new MappingMongoConverterParser());
registerBeanDefinitionParser("mongo", new MongoParser());
+ registerBeanDefinitionParser("mongo-client", new MongoClientParser());
registerBeanDefinitionParser("db-factory", new MongoDbFactoryParser());
registerBeanDefinitionParser("jmx", new MongoJmxParser());
registerBeanDefinitionParser("auditing", new MongoAuditingBeanDefinitionParser());
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoParser.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoParser.java
index ca605a02e2..604214f261 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoParser.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoParser.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2014 the original author or authors.
+ * Copyright 2011-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.
@@ -15,14 +15,10 @@
*/
package org.springframework.data.mongodb.config;
-import java.util.Map;
-
import org.springframework.beans.factory.config.BeanDefinition;
-import org.springframework.beans.factory.config.CustomEditorConfigurer;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
-import org.springframework.beans.factory.support.ManagedMap;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.data.config.BeanComponentDefinitionBuilder;
@@ -36,6 +32,7 @@
*
* @author Mark Pollack
* @author Oliver Gierke
+ * @author Christoph Strobl
*/
public class MongoParser implements BeanDefinitionParser {
@@ -64,7 +61,8 @@ public BeanDefinition parse(Element element, ParserContext parserContext) {
BeanComponentDefinition mongoComponent = helper.getComponent(builder, defaultedId);
parserContext.registerBeanComponent(mongoComponent);
- BeanComponentDefinition serverAddressPropertyEditor = helper.getComponent(registerServerAddressPropertyEditor());
+ BeanComponentDefinition serverAddressPropertyEditor = helper.getComponent(MongoParsingUtils
+ .getServerAddressPropertyEditorBuilder());
parserContext.registerBeanComponent(serverAddressPropertyEditor);
BeanComponentDefinition writeConcernPropertyEditor = helper.getComponent(MongoParsingUtils
.getWriteConcernPropertyEditorBuilder());
@@ -75,19 +73,4 @@ public BeanDefinition parse(Element element, ParserContext parserContext) {
return mongoComponent.getBeanDefinition();
}
- /**
- * One should only register one bean definition but want to have the convenience of using
- * AbstractSingleBeanDefinitionParser but have the side effect of registering a 'default' property editor with the
- * container.
- */
- private BeanDefinitionBuilder registerServerAddressPropertyEditor() {
-
- Map customEditors = new ManagedMap();
- customEditors.put("com.mongodb.ServerAddress[]",
- "org.springframework.data.mongodb.config.ServerAddressPropertyEditor");
-
- BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(CustomEditorConfigurer.class);
- builder.addPropertyValue("customEditors", customEditors);
- return builder;
- }
}
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoParsingUtils.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoParsingUtils.java
index 4ab0b2fc41..7d78b22a79 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoParsingUtils.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoParsingUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2013 the original author or authors.
+ * Copyright 2011-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.
@@ -24,6 +24,7 @@
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.ManagedMap;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
+import org.springframework.data.mongodb.core.MongoClientOptionsFactoryBean;
import org.springframework.data.mongodb.core.MongoOptionsFactoryBean;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
@@ -33,7 +34,8 @@
*
* @author Mark Pollack
* @author Oliver Gierke
- * @author Thomas Darimont
+ * @author Thomas Darimont
+ * @author Christoph Strobl
*/
abstract class MongoParsingUtils {
@@ -80,13 +82,54 @@ static boolean parseMongoOptions(Element element, BeanDefinitionBuilder mongoBui
setPropertyValue(optionsDefBuilder, optionsElement, "write-timeout", "writeTimeout");
setPropertyValue(optionsDefBuilder, optionsElement, "write-fsync", "writeFsync");
setPropertyValue(optionsDefBuilder, optionsElement, "slave-ok", "slaveOk");
- setPropertyValue(optionsDefBuilder, optionsElement, "ssl", "ssl");
- setPropertyReference(optionsDefBuilder, optionsElement, "ssl-socket-factory-ref", "sslSocketFactory");
+ setPropertyValue(optionsDefBuilder, optionsElement, "ssl", "ssl");
+ setPropertyReference(optionsDefBuilder, optionsElement, "ssl-socket-factory-ref", "sslSocketFactory");
mongoBuilder.addPropertyValue("mongoOptions", optionsDefBuilder.getBeanDefinition());
return true;
}
+ /**
+ * @param element
+ * @param mongoClientBuilder
+ * @return
+ * @since 1.7
+ */
+ public static boolean parseMongoClientOptions(Element element, BeanDefinitionBuilder mongoClientBuilder) {
+
+ Element optionsElement = DomUtils.getChildElementByTagName(element, "client-options");
+ if (optionsElement == null) {
+ return false;
+ }
+
+ BeanDefinitionBuilder clientOptionsDefBuilder = BeanDefinitionBuilder
+ .genericBeanDefinition(MongoClientOptionsFactoryBean.class);
+
+ setPropertyValue(clientOptionsDefBuilder, optionsElement, "description", "description");
+ setPropertyValue(clientOptionsDefBuilder, optionsElement, "min-connections-per-host", "minConnectionsPerHost");
+ setPropertyValue(clientOptionsDefBuilder, optionsElement, "connections-per-host", "connectionsPerHost");
+ setPropertyValue(clientOptionsDefBuilder, optionsElement, "threads-allowed-to-block-for-connection-multiplier",
+ "threadsAllowedToBlockForConnectionMultiplier");
+ setPropertyValue(clientOptionsDefBuilder, optionsElement, "max-wait-time", "maxWaitTime");
+ setPropertyValue(clientOptionsDefBuilder, optionsElement, "max-connection-idle-time", "maxConnectionIdleTime");
+ setPropertyValue(clientOptionsDefBuilder, optionsElement, "max-connection-life-time", "maxConnectionLifeTime");
+ setPropertyValue(clientOptionsDefBuilder, optionsElement, "connect-timeout", "connectTimeout");
+ setPropertyValue(clientOptionsDefBuilder, optionsElement, "socket-timeout", "socketTimeout");
+ setPropertyValue(clientOptionsDefBuilder, optionsElement, "socket-keep-alive", "socketKeepAlive");
+ setPropertyValue(clientOptionsDefBuilder, optionsElement, "read-preference", "readPreference");
+ setPropertyValue(clientOptionsDefBuilder, optionsElement, "write-concern", "writeConcern");
+ setPropertyValue(clientOptionsDefBuilder, optionsElement, "heartbeat-frequency", "heartbeatFrequency");
+ setPropertyValue(clientOptionsDefBuilder, optionsElement, "min-heartbeat-frequency", "minHeartbeatFrequency");
+ setPropertyValue(clientOptionsDefBuilder, optionsElement, "heartbeat-connect-timeout", "heartbeatConnectTimeout");
+ setPropertyValue(clientOptionsDefBuilder, optionsElement, "heartbeat-socket-timeout", "heartbeatSocketTimeout");
+ setPropertyValue(clientOptionsDefBuilder, optionsElement, "ssl", "ssl");
+ setPropertyReference(clientOptionsDefBuilder, optionsElement, "ssl-socket-factory-ref", "sslSocketFactory");
+
+ mongoClientBuilder.addPropertyValue("mongoClientOptions", clientOptionsDefBuilder.getBeanDefinition());
+
+ return true;
+ }
+
/**
* Returns the {@link BeanDefinitionBuilder} to build a {@link BeanDefinition} for a
* {@link WriteConcernPropertyEditor}.
@@ -103,4 +146,56 @@ static BeanDefinitionBuilder getWriteConcernPropertyEditorBuilder() {
return builder;
}
+
+ /**
+ * One should only register one bean definition but want to have the convenience of using
+ * AbstractSingleBeanDefinitionParser but have the side effect of registering a 'default' property editor with the
+ * container.
+ */
+ static BeanDefinitionBuilder getServerAddressPropertyEditorBuilder() {
+
+ Map customEditors = new ManagedMap();
+ customEditors.put("com.mongodb.ServerAddress[]",
+ "org.springframework.data.mongodb.config.ServerAddressPropertyEditor");
+
+ BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(CustomEditorConfigurer.class);
+ builder.addPropertyValue("customEditors", customEditors);
+ return builder;
+ }
+
+ /**
+ * Returns the {@link BeanDefinitionBuilder} to build a {@link BeanDefinition} for a
+ * {@link ReadPreferencePropertyEditor}.
+ *
+ * @return
+ * @since 1.7
+ */
+ static BeanDefinitionBuilder getReadPreferencePropertyEditorBuilder() {
+
+ Map> customEditors = new ManagedMap>();
+ customEditors.put("com.mongodb.ReadPreference", ReadPreferencePropertyEditor.class);
+
+ BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(CustomEditorConfigurer.class);
+ builder.addPropertyValue("customEditors", customEditors);
+
+ return builder;
+ }
+
+ /**
+ * Returns the {@link BeanDefinitionBuilder} to build a {@link BeanDefinition} for a
+ * {@link MongoCredentialPropertyEditor}.
+ *
+ * @return
+ * @since 1.7
+ */
+ static BeanDefinitionBuilder getMongoCredentialPropertyEditor() {
+
+ Map> customEditors = new ManagedMap>();
+ customEditors.put("com.mongodb.MongoCredential[]", MongoCredentialPropertyEditor.class);
+
+ BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(CustomEditorConfigurer.class);
+ builder.addPropertyValue("customEditors", customEditors);
+
+ return builder;
+ }
}
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/ReadPreferencePropertyEditor.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/ReadPreferencePropertyEditor.java
new file mode 100644
index 0000000000..9a6fa89587
--- /dev/null
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/ReadPreferencePropertyEditor.java
@@ -0,0 +1,61 @@
+/*
+ * 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.data.mongodb.config;
+
+import java.beans.PropertyEditorSupport;
+
+import com.mongodb.ReadPreference;
+
+/**
+ * Parse a {@link String} to a {@link ReadPreference}.
+ *
+ * @author Christoph Strobl
+ * @since 1.7
+ */
+public class ReadPreferencePropertyEditor extends PropertyEditorSupport {
+
+ @Override
+ public void setAsText(String readPreferenceString) throws IllegalArgumentException {
+
+ if (readPreferenceString == null) {
+ return;
+ }
+
+ ReadPreference preference = null;
+ try {
+ preference = ReadPreference.valueOf(readPreferenceString);
+ } catch (IllegalArgumentException ex) {
+ // ignore this one and try to map it differently
+ }
+
+ if (preference != null) {
+ setValue(preference);
+ } else if ("PRIMARY".equalsIgnoreCase(readPreferenceString)) {
+ setValue(ReadPreference.primary());
+ } else if ("PRIMARY_PREFERRED".equalsIgnoreCase(readPreferenceString)) {
+ setValue(ReadPreference.primaryPreferred());
+ } else if ("SECONDARY".equalsIgnoreCase(readPreferenceString)) {
+ setValue(ReadPreference.secondary());
+ } else if ("SECONDARY_PREFERRED".equalsIgnoreCase(readPreferenceString)) {
+ setValue(ReadPreference.secondaryPreferred());
+ } else if ("NEAREST".equalsIgnoreCase(readPreferenceString)) {
+ setValue(ReadPreference.nearest());
+ } else {
+ throw new IllegalArgumentException(String.format("Cannot find matching ReadPreference for %s",
+ readPreferenceString));
+ }
+ }
+}
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/DefaultIndexOperations.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/DefaultIndexOperations.java
index c971f66129..a1f2c96725 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/DefaultIndexOperations.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/DefaultIndexOperations.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2014 the original author or authors.
+ * Copyright 2011-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.
@@ -73,9 +73,9 @@ public void ensureIndex(final IndexDefinition indexDefinition) {
public Object doInCollection(DBCollection collection) throws MongoException, DataAccessException {
DBObject indexOptions = indexDefinition.getIndexOptions();
if (indexOptions != null) {
- collection.ensureIndex(indexDefinition.getIndexKeys(), indexOptions);
+ collection.createIndex(indexDefinition.getIndexKeys(), indexOptions);
} else {
- collection.ensureIndex(indexDefinition.getIndexKeys());
+ collection.createIndex(indexDefinition.getIndexKeys());
}
return null;
}
@@ -108,10 +108,12 @@ public void dropAllIndexes() {
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.IndexOperations#resetIndexCache()
*/
+ @Deprecated
public void resetIndexCache() {
mongoOperations.execute(collectionName, new CollectionCallback() {
public Void doInCollection(DBCollection collection) throws MongoException, DataAccessException {
- collection.resetIndexCache();
+
+ ReflectiveDBCollectionInvoker.resetIndexCache(collection);
return null;
}
});
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/IndexOperations.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/IndexOperations.java
index a4cb7e820b..8362b6196a 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/IndexOperations.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/IndexOperations.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011 the original author or authors.
+ * Copyright 2011-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.
@@ -20,12 +20,12 @@
import org.springframework.data.mongodb.core.index.IndexDefinition;
import org.springframework.data.mongodb.core.index.IndexInfo;
-
/**
* Index operations on a collection.
*
* @author Mark Pollack
* @author Oliver Gierke
+ * @author Christoph Strobl
*/
public interface IndexOperations {
@@ -51,7 +51,11 @@ public interface IndexOperations {
/**
* Clears all indices that have not yet been applied to this collection.
+ *
+ * @deprecated since 1.7. The mongo-java-driver version 3 does no longer support reseting the index cache.
+ * @throws {@link UnsupportedOperationException} when used with mongo-java-driver version 3.
*/
+ @Deprecated
void resetIndexCache();
/**
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoClientFactoryBean.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoClientFactoryBean.java
new file mode 100644
index 0000000000..c1c4edd61f
--- /dev/null
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoClientFactoryBean.java
@@ -0,0 +1,186 @@
+/*
+ * 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.data.mongodb.core;
+
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.beans.factory.FactoryBean;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.dao.DataAccessException;
+import org.springframework.dao.support.PersistenceExceptionTranslator;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.StringUtils;
+
+import com.mongodb.Mongo;
+import com.mongodb.MongoClient;
+import com.mongodb.MongoClientOptions;
+import com.mongodb.MongoCredential;
+import com.mongodb.ServerAddress;
+
+/**
+ * Convenient factory for configuring MongoDB.
+ *
+ * @author Christoph Strobl
+ * @since 1.7
+ */
+public class MongoClientFactoryBean implements FactoryBean, InitializingBean, DisposableBean,
+ PersistenceExceptionTranslator {
+
+ private MongoClient mongo;
+
+ private MongoClientOptions mongoClientOptions;
+
+ private String host;
+ private Integer port;
+ private List replicaSetSeeds;
+ private List credentials;
+
+ private PersistenceExceptionTranslator exceptionTranslator = new MongoExceptionTranslator();
+
+ /**
+ * Set the {@link MongoClientOptions} to be used when creating {@link MongoClient}.
+ *
+ * @param mongoClientOptions
+ */
+ public void setMongoClientOptions(MongoClientOptions mongoClientOptions) {
+ this.mongoClientOptions = mongoClientOptions;
+ }
+
+ /**
+ * Set the list of credentials to be used when creating {@link MongoClient}.
+ *
+ * @param credentials can be {@literal null}.
+ */
+ public void setCredentials(MongoCredential[] credentials) {
+ this.credentials = filterNonNullElementsAsList(credentials);
+ }
+
+ public void setReplicaSetSeeds(ServerAddress[] replicaSetSeeds) {
+ this.replicaSetSeeds = filterNonNullElementsAsList(replicaSetSeeds);
+ }
+
+ /**
+ * @param elements the elements to filter
+ * @return a new unmodifiable {@link List#} from the given elements without nulls
+ */
+ private List filterNonNullElementsAsList(T[] elements) {
+
+ if (elements == null) {
+ return Collections.emptyList();
+ }
+
+ List candidateElements = new ArrayList();
+
+ for (T element : elements) {
+ if (element != null) {
+ candidateElements.add(element);
+ }
+ }
+
+ return Collections.unmodifiableList(candidateElements);
+ }
+
+ public void setHost(String host) {
+ this.host = host;
+ }
+
+ public void setPort(int port) {
+ this.port = port;
+ }
+
+ /**
+ * @param exceptionTranslator
+ */
+ public void setExceptionTranslator(PersistenceExceptionTranslator exceptionTranslator) {
+ this.exceptionTranslator = exceptionTranslator;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.beans.factory.FactoryBean#getObject()
+ */
+ public Mongo getObject() throws Exception {
+ return mongo;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.beans.factory.FactoryBean#getObjectType()
+ */
+ public Class extends Mongo> getObjectType() {
+ return Mongo.class;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.beans.factory.FactoryBean#isSingleton()
+ */
+ public boolean isSingleton() {
+ return true;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.dao.support.PersistenceExceptionTranslator#translateExceptionIfPossible(java.lang.RuntimeException)
+ */
+ public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
+ return exceptionTranslator.translateExceptionIfPossible(ex);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
+ */
+ public void afterPropertiesSet() throws Exception {
+
+ if (mongoClientOptions == null) {
+ mongoClientOptions = MongoClientOptions.builder().build();
+ }
+ if (credentials == null) {
+ credentials = Collections.emptyList();
+ }
+
+ this.mongo = createMongoClient();
+ }
+
+ private MongoClient createMongoClient() throws UnknownHostException {
+
+ if (!CollectionUtils.isEmpty(replicaSetSeeds)) {
+ return new MongoClient(replicaSetSeeds, credentials, mongoClientOptions);
+ }
+
+ return new MongoClient(createConfiguredOrDefaultServerAddress(), credentials, mongoClientOptions);
+ }
+
+ private ServerAddress createConfiguredOrDefaultServerAddress() throws UnknownHostException {
+
+ ServerAddress defaultAddress = new ServerAddress();
+ return new ServerAddress(StringUtils.hasText(host) ? host : defaultAddress.getHost(),
+ port != null ? port.intValue() : defaultAddress.getPort());
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.beans.factory.DisposableBean#destroy()
+ */
+ public void destroy() throws Exception {
+ this.mongo.close();
+ }
+}
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoClientOptionsFactoryBean.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoClientOptionsFactoryBean.java
new file mode 100644
index 0000000000..8856815e1d
--- /dev/null
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoClientOptionsFactoryBean.java
@@ -0,0 +1,309 @@
+/*
+ * 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.data.mongodb.core;
+
+import javax.net.SocketFactory;
+import javax.net.ssl.SSLSocketFactory;
+
+import org.springframework.beans.factory.FactoryBean;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.data.mongodb.MongoDbFactory;
+
+import com.mongodb.DBDecoderFactory;
+import com.mongodb.DBEncoderFactory;
+import com.mongodb.MongoClientOptions;
+import com.mongodb.ReadPreference;
+import com.mongodb.WriteConcern;
+
+/**
+ * A factory bean for construction of a {@link MongoClientOptions} instance.
+ *
+ * @author Christoph Strobl
+ * @since 1.7
+ */
+public class MongoClientOptionsFactoryBean implements FactoryBean, InitializingBean {
+
+ private static final MongoClientOptions DEFAULT_MONGO_OPTIONS = MongoClientOptions.builder().build();
+
+ private String description = DEFAULT_MONGO_OPTIONS.getDescription();
+ private int minConnectionsPerHost = DEFAULT_MONGO_OPTIONS.getMinConnectionsPerHost();
+ private int connectionsPerHost = DEFAULT_MONGO_OPTIONS.getConnectionsPerHost();
+ private int threadsAllowedToBlockForConnectionMultiplier = DEFAULT_MONGO_OPTIONS
+ .getThreadsAllowedToBlockForConnectionMultiplier();
+ private int maxWaitTime = DEFAULT_MONGO_OPTIONS.getMaxWaitTime();
+ private int maxConnectionIdleTime = DEFAULT_MONGO_OPTIONS.getMaxConnectionIdleTime();
+ private int maxConnectionLifeTime = DEFAULT_MONGO_OPTIONS.getMaxConnectionLifeTime();
+ private int connectTimeout = DEFAULT_MONGO_OPTIONS.getConnectTimeout();
+ private int socketTimeout = DEFAULT_MONGO_OPTIONS.getSocketTimeout();
+ private boolean socketKeepAlive = DEFAULT_MONGO_OPTIONS.isSocketKeepAlive();
+ private ReadPreference readPreference = DEFAULT_MONGO_OPTIONS.getReadPreference();
+ private DBDecoderFactory dbDecoderFactory = DEFAULT_MONGO_OPTIONS.getDbDecoderFactory();
+ private DBEncoderFactory dbEncoderFactory = DEFAULT_MONGO_OPTIONS.getDbEncoderFactory();
+ private WriteConcern writeConcern = DEFAULT_MONGO_OPTIONS.getWriteConcern();
+ private SocketFactory socketFactory = DEFAULT_MONGO_OPTIONS.getSocketFactory();
+ private boolean cursorFinalizerEnabled = DEFAULT_MONGO_OPTIONS.isCursorFinalizerEnabled();
+ private boolean alwaysUseMBeans = DEFAULT_MONGO_OPTIONS.isAlwaysUseMBeans();
+ private int heartbeatFrequency = DEFAULT_MONGO_OPTIONS.getHeartbeatFrequency();
+ private int minHeartbeatFrequency = DEFAULT_MONGO_OPTIONS.getMinHeartbeatFrequency();
+ private int heartbeatConnectTimeout = DEFAULT_MONGO_OPTIONS.getHeartbeatConnectTimeout();
+ private int heartbeatSocketTimeout = DEFAULT_MONGO_OPTIONS.getHeartbeatSocketTimeout();
+ private String requiredReplicaSetName = DEFAULT_MONGO_OPTIONS.getRequiredReplicaSetName();
+
+ private boolean ssl;
+ private SSLSocketFactory sslSocketFactory;
+
+ private MongoClientOptions clientOptions;
+
+ /**
+ * Set the MongoClient description.
+ *
+ * @param description
+ */
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ /**
+ * Set the minimum number of connections per host.
+ *
+ * @param minConnectionsPerHost
+ */
+ public void setMinConnectionsPerHost(int minConnectionsPerHost) {
+ this.minConnectionsPerHost = minConnectionsPerHost;
+ }
+
+ /**
+ * Set the number of connections allowed per host. Will block if run out. Default is 10. System property
+ * {@code MONGO.POOLSIZE} can override
+ *
+ * @param connectionsPerHost
+ */
+ public void setConnectionsPerHost(int connectionsPerHost) {
+ this.connectionsPerHost = connectionsPerHost;
+ }
+
+ /**
+ * Set the multiplier for connectionsPerHost for # of threads that can block. Default is 5. If connectionsPerHost is
+ * 10, and threadsAllowedToBlockForConnectionMultiplier is 5, then 50 threads can block more than that and an
+ * exception will be thrown.
+ *
+ * @param threadsAllowedToBlockForConnectionMultiplier
+ */
+ public void setThreadsAllowedToBlockForConnectionMultiplier(int threadsAllowedToBlockForConnectionMultiplier) {
+ this.threadsAllowedToBlockForConnectionMultiplier = threadsAllowedToBlockForConnectionMultiplier;
+ }
+
+ /**
+ * Set the max wait time of a blocking thread for a connection. Default is 12000 ms (2 minutes)
+ *
+ * @param maxWaitTime
+ */
+ public void setMaxWaitTime(int maxWaitTime) {
+ this.maxWaitTime = maxWaitTime;
+ }
+
+ /**
+ * The maximum idle time for a pooled connection.
+ *
+ * @param maxConnectionIdleTime
+ */
+ public void setMaxConnectionIdleTime(int maxConnectionIdleTime) {
+ this.maxConnectionIdleTime = maxConnectionIdleTime;
+ }
+
+ /**
+ * Set the maximum life time for a pooled connection.
+ *
+ * @param maxConnectionLifeTime
+ */
+ public void setMaxConnectionLifeTime(int maxConnectionLifeTime) {
+ this.maxConnectionLifeTime = maxConnectionLifeTime;
+ }
+
+ /**
+ * Set the connect timeout in milliseconds. 0 is default and infinite.
+ *
+ * @param connectTimeout
+ */
+ public void setConnectTimeout(int connectTimeout) {
+ this.connectTimeout = connectTimeout;
+ }
+
+ /**
+ * Set the socket timeout. 0 is default and infinite.
+ *
+ * @param socketTimeout
+ */
+ public void setSocketTimeout(int socketTimeout) {
+ this.socketTimeout = socketTimeout;
+ }
+
+ /**
+ * Set the keep alive flag, controls whether or not to have socket keep alive timeout. Defaults to false.
+ *
+ * @param socketKeepAlive
+ */
+ public void setSocketKeepAlive(boolean socketKeepAlive) {
+ this.socketKeepAlive = socketKeepAlive;
+ }
+
+ /**
+ * Set the {@link ReadPreference}.
+ *
+ * @param readPreference
+ */
+ public void setReadPreference(ReadPreference readPreference) {
+ this.readPreference = readPreference;
+ }
+
+ /**
+ * Set the {@link WriteConcern} that will be the default value used when asking the {@link MongoDbFactory} for a DB
+ * object.
+ *
+ * @param writeConcern
+ */
+ public void setWriteConcern(WriteConcern writeConcern) {
+ this.writeConcern = writeConcern;
+ }
+
+ /**
+ * @param socketFactory
+ */
+ public void setSocketFactory(SocketFactory socketFactory) {
+ this.socketFactory = socketFactory;
+ }
+
+ /**
+ * Set the frequency that the driver will attempt to determine the current state of each server in the cluster.
+ *
+ * @param heartbeatFrequency
+ */
+ public void setHeartbeatFrequency(int heartbeatFrequency) {
+ this.heartbeatFrequency = heartbeatFrequency;
+ }
+
+ /**
+ * In the event that the driver has to frequently re-check a server's availability, it will wait at least this long
+ * since the previous check to avoid wasted effort.
+ *
+ * @param minHeartbeatFrequency
+ */
+ public void setMinHeartbeatFrequency(int minHeartbeatFrequency) {
+ this.minHeartbeatFrequency = minHeartbeatFrequency;
+ }
+
+ /**
+ * Set the connect timeout for connections used for the cluster heartbeat.
+ *
+ * @param heartbeatConnectTimeout
+ */
+ public void setHeartbeatConnectTimeout(int heartbeatConnectTimeout) {
+ this.heartbeatConnectTimeout = heartbeatConnectTimeout;
+ }
+
+ /**
+ * Set the socket timeout for connections used for the cluster heartbeat.
+ *
+ * @param heartbeatSocketTimeout
+ */
+ public void setHeartbeatSocketTimeout(int heartbeatSocketTimeout) {
+ this.heartbeatSocketTimeout = heartbeatSocketTimeout;
+ }
+
+ /**
+ * @param requiredReplicaSetName
+ */
+ public void setRequiredReplicaSetName(String requiredReplicaSetName) {
+ this.requiredReplicaSetName = requiredReplicaSetName;
+ }
+
+ /**
+ * This controls if the driver should us an SSL connection. Defaults to false.
+ *
+ * @param ssl
+ */
+ public void setSsl(boolean ssl) {
+ this.ssl = ssl;
+ }
+
+ /**
+ * Set the {@link SSLSocketFactory} to use for the {@literal SSL} connection. If none is configured here,
+ * {@link SSLSocketFactory#getDefault()} will be used.
+ *
+ * @param sslSocketFactory
+ */
+ public void setSslSocketFactory(SSLSocketFactory sslSocketFactory) {
+ this.sslSocketFactory = sslSocketFactory;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
+ */
+ public void afterPropertiesSet() {
+
+ SocketFactory socketFactoryToUse = ssl ? (sslSocketFactory != null ? sslSocketFactory : SSLSocketFactory
+ .getDefault()) : this.socketFactory;
+
+ this.clientOptions = MongoClientOptions.builder() //
+ .alwaysUseMBeans(this.alwaysUseMBeans) //
+ .connectionsPerHost(this.connectionsPerHost) //
+ .connectTimeout(connectTimeout) //
+ .cursorFinalizerEnabled(cursorFinalizerEnabled) //
+ .dbDecoderFactory(dbDecoderFactory) //
+ .dbEncoderFactory(dbEncoderFactory) //
+ .description(description) //
+ .heartbeatConnectTimeout(heartbeatConnectTimeout) //
+ .heartbeatFrequency(heartbeatFrequency) //
+ .heartbeatSocketTimeout(heartbeatSocketTimeout) //
+ .maxConnectionIdleTime(maxConnectionIdleTime) //
+ .maxConnectionLifeTime(maxConnectionLifeTime) //
+ .maxWaitTime(maxWaitTime) //
+ .minConnectionsPerHost(minConnectionsPerHost) //
+ .minHeartbeatFrequency(minHeartbeatFrequency) //
+ .readPreference(readPreference) //
+ .requiredReplicaSetName(requiredReplicaSetName) //
+ .socketFactory(socketFactoryToUse) //
+ .socketKeepAlive(socketKeepAlive) //
+ .socketTimeout(socketTimeout) //
+ .threadsAllowedToBlockForConnectionMultiplier(threadsAllowedToBlockForConnectionMultiplier) //
+ .writeConcern(writeConcern).build();
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.beans.factory.FactoryBean#getObject()
+ */
+ public MongoClientOptions getObject() {
+ return this.clientOptions;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.beans.factory.FactoryBean#getObjectType()
+ */
+ public Class> getObjectType() {
+ return MongoClientOptions.class;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.beans.factory.FactoryBean#isSingleton()
+ */
+ public boolean isSingleton() {
+ return true;
+ }
+}
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoDbUtils.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoDbUtils.java
index 11a46bda61..0985abcf73 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoDbUtils.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoDbUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2010-2013 the original author or authors.
+ * Copyright 2010-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.
@@ -18,12 +18,13 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.authentication.UserCredentials;
-import org.springframework.data.mongodb.CannotGetMongoDbConnectionException;
+import org.springframework.data.mongodb.MongoClientVersion;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.Assert;
import com.mongodb.DB;
import com.mongodb.Mongo;
+import com.mongodb.MongoClient;
/**
* Helper class featuring helper methods for internal MongoDb classes. Mainly intended for internal use within the
@@ -34,6 +35,7 @@
* @author Oliver Gierke
* @author Randy Watler
* @author Thomas Darimont
+ * @author Christoph Strobl
* @since 1.0
*/
public abstract class MongoDbUtils {
@@ -65,11 +67,24 @@ public static DB getDB(Mongo mongo, String databaseName) {
* @param databaseName the database name, must not be {@literal null} or empty.
* @param credentials the credentials to use, must not be {@literal null}.
* @return the {@link DB} connection
+ * @deprecated since 1.7. The {@link MongoClient} itself should hold credentials within
+ * {@link MongoClient#getCredentialsList()}.
*/
+ @Deprecated
public static DB getDB(Mongo mongo, String databaseName, UserCredentials credentials) {
return getDB(mongo, databaseName, credentials, databaseName);
}
+ /**
+ * @param mongo
+ * @param databaseName
+ * @param credentials
+ * @param authenticationDatabaseName
+ * @return
+ * @deprecated since 1.7. The {@link MongoClient} itself should hold credentials within
+ * {@link MongoClient#getCredentialsList()}.
+ */
+ @Deprecated
public static DB getDB(Mongo mongo, String databaseName, UserCredentials credentials,
String authenticationDatabaseName) {
@@ -109,22 +124,9 @@ private static DB doGetDB(Mongo mongo, String databaseName, UserCredentials cred
LOGGER.debug("Getting Mongo Database name=[{}]", databaseName);
DB db = mongo.getDB(databaseName);
- boolean credentialsGiven = credentials.hasUsername() && credentials.hasPassword();
-
- DB authDb = databaseName.equals(authenticationDatabaseName) ? db : mongo.getDB(authenticationDatabaseName);
-
- synchronized (authDb) {
-
- if (credentialsGiven && !authDb.isAuthenticated()) {
- String username = credentials.getUsername();
- String password = credentials.hasPassword() ? credentials.getPassword() : null;
-
- if (!authDb.authenticate(username, password == null ? null : password.toCharArray())) {
- throw new CannotGetMongoDbConnectionException("Failed to authenticate to database [" + databaseName + "], "
- + credentials.toString(), databaseName, credentials);
- }
- }
+ if (requiresAuthDbAuthentication(credentials)) {
+ ReflectiveDbInvoker.authenticate(mongo, db, credentials, authenticationDatabaseName);
}
// TX sync active, bind new database to thread
@@ -181,16 +183,37 @@ public static boolean isDBTransactional(DB db, Mongo mongo) {
* Perform actual closing of the Mongo DB object, catching and logging any cleanup exceptions thrown.
*
* @param db the DB to close (may be null)
+ * @deprecated since 1.7. The main use case for this method is to ensure that applications can read their own
+ * unacknowledged writes, but this is no longer so prevalent since the mongo-java-driver version 3 started
+ * defaulting to acknowledged writes.
*/
+ @Deprecated
public static void closeDB(DB db) {
if (db != null) {
LOGGER.debug("Closing Mongo DB object");
try {
- db.requestDone();
+ ReflectiveDbInvoker.requestDone(db);
} catch (Throwable ex) {
LOGGER.debug("Unexpected exception on closing Mongo DB object", ex);
}
}
}
+
+ /**
+ * Check if credentials present. In case we're using a monog-java-driver version 3 or above we do not have the need
+ * for authentication as the auth data has to be provied within the MongoClient
+ *
+ * @param credentials
+ * @return
+ */
+ private static boolean requiresAuthDbAuthentication(UserCredentials credentials) {
+
+ if (credentials == null || !credentials.hasUsername()) {
+ return false;
+ }
+
+ return !MongoClientVersion.isMongo3Driver();
+ }
+
}
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoExceptionTranslator.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoExceptionTranslator.java
index b8eeb427dd..9be051e309 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoExceptionTranslator.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoExceptionTranslator.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2010-2013 the original author or authors.
+ * Copyright 2010-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.
@@ -15,23 +15,21 @@
*/
package org.springframework.data.mongodb.core;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataAccessResourceFailureException;
+import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.dao.InvalidDataAccessResourceUsageException;
import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.data.mongodb.UncategorizedMongoDbException;
+import org.springframework.util.ClassUtils;
-import com.mongodb.MongoCursorNotFoundException;
import com.mongodb.MongoException;
-import com.mongodb.MongoException.CursorNotFound;
-import com.mongodb.MongoException.DuplicateKey;
-import com.mongodb.MongoException.Network;
-import com.mongodb.MongoInternalException;
-import com.mongodb.MongoServerSelectionException;
-import com.mongodb.MongoSocketException;
-import com.mongodb.MongoTimeoutException;
/**
* Simple {@link PersistenceExceptionTranslator} for Mongo. Convert the given runtime exception to an appropriate
@@ -40,9 +38,23 @@
*
* @author Oliver Gierke
* @author Michal Vich
+ * @author Christoph Strobl
*/
public class MongoExceptionTranslator implements PersistenceExceptionTranslator {
+ private static final Set DULICATE_KEY_EXCEPTIONS = new HashSet(Arrays.asList(
+ "MongoException.DuplicateKey", "DuplicateKeyException"));
+
+ private static final Set RESOURCE_FAILURE_EXCEPTIONS = new HashSet(Arrays.asList(
+ "MongoException.Network", "MongoSocketException", "MongoException.CursorNotFound",
+ "MongoCursorNotFoundException", "MongoServerSelectionException", "MongoTimeoutException"));
+
+ private static final Set RESOURCE_USAGE_EXCEPTIONS = new HashSet(
+ Arrays.asList("MongoInternalException"));
+
+ private static final Set DATA_INTEGRETY_EXCEPTIONS = new HashSet(
+ Arrays.asList("WriteConcernException"));
+
/*
* (non-Javadoc)
* @see org.springframework.dao.support.PersistenceExceptionTranslator#translateExceptionIfPossible(java.lang.RuntimeException)
@@ -51,28 +63,22 @@ public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
// Check for well-known MongoException subclasses.
- if (ex instanceof DuplicateKey || ex instanceof DuplicateKeyException) {
- return new DuplicateKeyException(ex.getMessage(), ex);
- }
+ String exception = ClassUtils.getShortName(ClassUtils.getUserClass(ex.getClass()));
- if (ex instanceof Network || ex instanceof MongoSocketException) {
- return new DataAccessResourceFailureException(ex.getMessage(), ex);
- }
-
- if (ex instanceof CursorNotFound || ex instanceof MongoCursorNotFoundException) {
- return new DataAccessResourceFailureException(ex.getMessage(), ex);
+ if (DULICATE_KEY_EXCEPTIONS.contains(exception)) {
+ return new DuplicateKeyException(ex.getMessage(), ex);
}
- if (ex instanceof MongoServerSelectionException) {
+ if (RESOURCE_FAILURE_EXCEPTIONS.contains(exception)) {
return new DataAccessResourceFailureException(ex.getMessage(), ex);
}
- if (ex instanceof MongoTimeoutException) {
- return new DataAccessResourceFailureException(ex.getMessage(), ex);
+ if (RESOURCE_USAGE_EXCEPTIONS.contains(exception)) {
+ return new InvalidDataAccessResourceUsageException(ex.getMessage(), ex);
}
- if (ex instanceof MongoInternalException) {
- return new InvalidDataAccessResourceUsageException(ex.getMessage(), ex);
+ if (DATA_INTEGRETY_EXCEPTIONS.contains(exception)) {
+ return new DataIntegrityViolationException(ex.getMessage(), ex);
}
// All other MongoExceptions
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoFactoryBean.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoFactoryBean.java
index a7c156144f..41699be8e6 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoFactoryBean.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoFactoryBean.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2010-2013 the original author or authors.
+ * Copyright 2010-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.
@@ -15,6 +15,7 @@
*/
package org.springframework.data.mongodb.core;
+import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -40,14 +41,18 @@
* @author Graeme Rocher
* @author Oliver Gierke
* @author Thomas Darimont
+ * @author Christoph Strobl
* @since 1.0
+ * @deprecated since 1.7. Please use {@link MongoClientFactoryBean} instead.
*/
+@Deprecated
public class MongoFactoryBean implements FactoryBean, InitializingBean, DisposableBean,
PersistenceExceptionTranslator {
private Mongo mongo;
private MongoOptions mongoOptions;
+
private String host;
private Integer port;
private WriteConcern writeConcern;
@@ -56,6 +61,9 @@ public class MongoFactoryBean implements FactoryBean, InitializingBean, D
private PersistenceExceptionTranslator exceptionTranslator = new MongoExceptionTranslator();
+ /**
+ * @param mongoOptions
+ */
public void setMongoOptions(MongoOptions mongoOptions) {
this.mongoOptions = mongoOptions;
}
@@ -66,7 +74,6 @@ public void setReplicaSetSeeds(ServerAddress[] replicaSetSeeds) {
/**
* @deprecated use {@link #setReplicaSetSeeds(ServerAddress[])} instead
- *
* @param replicaPair
*/
@Deprecated
@@ -148,8 +155,11 @@ public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
* (non-Javadoc)
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
*/
- @SuppressWarnings("deprecation")
public void afterPropertiesSet() throws Exception {
+ this.mongo = createMongo();
+ }
+
+ private Mongo createMongo() throws UnknownHostException {
Mongo mongo;
ServerAddress defaultOptions = new ServerAddress();
@@ -175,7 +185,7 @@ public void afterPropertiesSet() throws Exception {
mongo.setWriteConcern(writeConcern);
}
- this.mongo = mongo;
+ return mongo;
}
private boolean isNullOrEmpty(Collection> elements) {
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoOperations.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoOperations.java
index e38912bfe9..24748a86b8 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoOperations.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoOperations.java
@@ -35,8 +35,10 @@
import org.springframework.data.mongodb.core.query.Update;
import com.mongodb.CommandResult;
+import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBObject;
+import com.mongodb.ReadPreference;
import com.mongodb.WriteResult;
/**
@@ -85,9 +87,23 @@ public interface MongoOperations {
*
* @param command a MongoDB command
* @param options query options to use
+ * @deprecated since 1.7. Please use {@link #executeCommand(DBObject, ReadPreference)}, as the mongo-java-driver
+ * version 3 no longer supports this operation.
*/
+ @Deprecated
CommandResult executeCommand(DBObject command, int options);
+ /**
+ * Execute a MongoDB command. Any errors that result from executing this command will be converted into Spring's DAO
+ * exception hierarchy.
+ *
+ * @param command a MongoDB command.
+ * @param readPreference read preferences to use.
+ * @return
+ * @since 1.7
+ */
+ CommandResult executeCommand(DBObject command, ReadPreference readPreference);
+
/**
* Execute a MongoDB query and iterate over the query results on a per-document basis with a DocumentCallbackHandler.
*
@@ -143,7 +159,10 @@ public interface MongoOperations {
* @param return type
* @param action callback that specified the MongoDB actions to perform on the DB instance
* @return a result object returned by the action or null
+ * @deprecated since 1.7 as the mongo-java-driver version 3 does not longer support request boundaries via
+ * {@link DB#requestStart()} and {@link DB#requestDone()}.
*/
+ @Deprecated
T executeInSession(DbCallback action);
/**
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoOptionsFactoryBean.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoOptionsFactoryBean.java
index 63a1075748..72a05aa97d 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoOptionsFactoryBean.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoOptionsFactoryBean.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2010-2014 the original author or authors.
+ * Copyright 2010-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.
@@ -19,34 +19,44 @@
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
+import org.springframework.data.mongodb.MongoClientVersion;
import com.mongodb.MongoOptions;
/**
- * A factory bean for construction of a {@link MongoOptions} instance.
+ * A factory bean for construction of a {@link MongoOptions} instance. In case used with mongo-java-driver version 3
+ * porperties not suppprted by the driver will be ignored.
*
* @author Graeme Rocher
* @author Mark Pollack
* @author Mike Saavedra
* @author Thomas Darimont
+ * @author Christoph Strobl
+ * @deprecated since 1.7. Please use {@link MongoClientOptionsFactoryBean} instead.
*/
-@SuppressWarnings("deprecation")
+@Deprecated
public class MongoOptionsFactoryBean implements FactoryBean, InitializingBean {
private static final MongoOptions DEFAULT_MONGO_OPTIONS = new MongoOptions();
- private int connectionsPerHost = DEFAULT_MONGO_OPTIONS.connectionsPerHost;
- private int threadsAllowedToBlockForConnectionMultiplier = DEFAULT_MONGO_OPTIONS.threadsAllowedToBlockForConnectionMultiplier;
- private int maxWaitTime = DEFAULT_MONGO_OPTIONS.maxWaitTime;
- private int connectTimeout = DEFAULT_MONGO_OPTIONS.connectTimeout;
- private int socketTimeout = DEFAULT_MONGO_OPTIONS.socketTimeout;
- private boolean socketKeepAlive = DEFAULT_MONGO_OPTIONS.socketKeepAlive;
- private boolean autoConnectRetry = DEFAULT_MONGO_OPTIONS.autoConnectRetry;
- private long maxAutoConnectRetryTime = DEFAULT_MONGO_OPTIONS.maxAutoConnectRetryTime;
- private int writeNumber = DEFAULT_MONGO_OPTIONS.w;
- private int writeTimeout = DEFAULT_MONGO_OPTIONS.wtimeout;
- private boolean writeFsync = DEFAULT_MONGO_OPTIONS.fsync;
- private boolean slaveOk = DEFAULT_MONGO_OPTIONS.slaveOk;
+ private int connectionsPerHost = DEFAULT_MONGO_OPTIONS.getConnectionsPerHost();
+ private int threadsAllowedToBlockForConnectionMultiplier = DEFAULT_MONGO_OPTIONS
+ .getThreadsAllowedToBlockForConnectionMultiplier();
+ private int maxWaitTime = DEFAULT_MONGO_OPTIONS.getMaxWaitTime();
+ private int connectTimeout = DEFAULT_MONGO_OPTIONS.getConnectTimeout();
+ private int socketTimeout = DEFAULT_MONGO_OPTIONS.getSocketTimeout();
+ private boolean socketKeepAlive = DEFAULT_MONGO_OPTIONS.isSocketKeepAlive();
+ private int writeNumber = DEFAULT_MONGO_OPTIONS.getW();
+ private int writeTimeout = DEFAULT_MONGO_OPTIONS.getWtimeout();
+ private boolean writeFsync = DEFAULT_MONGO_OPTIONS.isFsync();
+
+ private boolean autoConnectRetry = !MongoClientVersion.isMongo3Driver() ? ReflectiveMongoOptionsInvoker
+ .getAutoConnectRetry(DEFAULT_MONGO_OPTIONS) : false;
+ private long maxAutoConnectRetryTime = !MongoClientVersion.isMongo3Driver() ? ReflectiveMongoOptionsInvoker
+ .getMaxAutoConnectRetryTime(DEFAULT_MONGO_OPTIONS) : -1;
+ private boolean slaveOk = !MongoClientVersion.isMongo3Driver() ? ReflectiveMongoOptionsInvoker
+ .getSlaveOk(DEFAULT_MONGO_OPTIONS) : false;
+
private boolean ssl;
private SSLSocketFactory sslSocketFactory;
@@ -144,7 +154,10 @@ public void setWriteFsync(boolean writeFsync) {
/**
* Configures whether or not the system retries automatically on a failed connect. This defaults to {@literal false}.
+ *
+ * @deprecated since 1.7.
*/
+ @Deprecated
public void setAutoConnectRetry(boolean autoConnectRetry) {
this.autoConnectRetry = autoConnectRetry;
}
@@ -154,7 +167,9 @@ public void setAutoConnectRetry(boolean autoConnectRetry) {
* defaults to {@literal 0}, which means to use the default {@literal 15s} if {@link #autoConnectRetry} is on.
*
* @param maxAutoConnectRetryTime the maxAutoConnectRetryTime to set
+ * @deprecated since 1.7
*/
+ @Deprecated
public void setMaxAutoConnectRetryTime(long maxAutoConnectRetryTime) {
this.maxAutoConnectRetryTime = maxAutoConnectRetryTime;
}
@@ -163,7 +178,9 @@ public void setMaxAutoConnectRetryTime(long maxAutoConnectRetryTime) {
* Specifies if the driver is allowed to read from secondaries or slaves. Defaults to {@literal false}.
*
* @param slaveOk true if the driver should read from secondaries or slaves.
+ * @deprecated since 1.7
*/
+ @Deprecated
public void setSlaveOk(boolean slaveOk) {
this.slaveOk = slaveOk;
}
@@ -200,25 +217,33 @@ public void setSslSocketFactory(SSLSocketFactory sslSocketFactory) {
*/
public void afterPropertiesSet() {
+ if (MongoClientVersion.isMongo3Driver()) {
+ throw new IllegalArgumentException(
+ String
+ .format("Usage of 'mongo-options' is no longer supported for mongo-java-driver version 3 and above. Please use 'mongo-client-options' and refer to chapter 'MongoDB 3.0 Support' for details."));
+ }
+
MongoOptions options = new MongoOptions();
- options.connectionsPerHost = connectionsPerHost;
- options.threadsAllowedToBlockForConnectionMultiplier = threadsAllowedToBlockForConnectionMultiplier;
- options.maxWaitTime = maxWaitTime;
- options.connectTimeout = connectTimeout;
- options.socketTimeout = socketTimeout;
- options.socketKeepAlive = socketKeepAlive;
- options.autoConnectRetry = autoConnectRetry;
- options.maxAutoConnectRetryTime = maxAutoConnectRetryTime;
- options.slaveOk = slaveOk;
- options.w = writeNumber;
- options.wtimeout = writeTimeout;
- options.fsync = writeFsync;
+ options.setConnectionsPerHost(connectionsPerHost);
+ options.setThreadsAllowedToBlockForConnectionMultiplier(threadsAllowedToBlockForConnectionMultiplier);
+ options.setMaxWaitTime(maxWaitTime);
+ options.setConnectTimeout(connectTimeout);
+ options.setSocketTimeout(socketTimeout);
+ options.setSocketKeepAlive(socketKeepAlive);
+
+ options.setW(writeNumber);
+ options.setWtimeout(writeTimeout);
+ options.setFsync(writeFsync);
if (ssl) {
options.setSocketFactory(sslSocketFactory != null ? sslSocketFactory : SSLSocketFactory.getDefault());
}
+ ReflectiveMongoOptionsInvoker.setAutoConnectRetry(options, autoConnectRetry);
+ ReflectiveMongoOptionsInvoker.setMaxAutoConnectRetryTime(options, maxAutoConnectRetryTime);
+ ReflectiveMongoOptionsInvoker.setSlaveOk(options, slaveOk);
+
this.options = options;
}
@@ -245,4 +270,5 @@ public Class> getObjectType() {
public boolean isSingleton() {
return true;
}
+
}
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java
index f8f391c3da..96105e3ab1 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2010-2014 the original author or authors.
+ * Copyright 2010-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.
@@ -59,6 +59,7 @@
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mapping.model.ConvertingPropertyAccessor;
import org.springframework.data.mapping.model.MappingException;
+import org.springframework.data.mongodb.MongoClientVersion;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationOperationContext;
@@ -98,10 +99,12 @@
import org.springframework.jca.cci.core.ConnectionCallback;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
+import org.springframework.util.ObjectUtils;
import org.springframework.util.ResourceUtils;
import org.springframework.util.StringUtils;
import com.mongodb.BasicDBObject;
+import com.mongodb.Bytes;
import com.mongodb.CommandResult;
import com.mongodb.DB;
import com.mongodb.DBCollection;
@@ -332,11 +335,25 @@ public CommandResult doInDB(DB db) throws MongoException, DataAccessException {
return result;
}
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.mongodb.core.MongoOperations#executeCommand(com.mongodb.DBObject, int)
+ */
+ @Deprecated
public CommandResult executeCommand(final DBObject command, final int options) {
+ return executeCommand(command, (options & Bytes.QUERYOPTION_SLAVEOK) != 0 ? ReadPreference.secondaryPreferred()
+ : ReadPreference.primary());
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.mongodb.core.MongoOperations#executeCommand(com.mongodb.DBObject, com.mongodb.ReadPreference)
+ */
+ public CommandResult executeCommand(final DBObject command, final ReadPreference readPreference) {
CommandResult result = execute(new DbCallback() {
public CommandResult doInDB(DB db) throws MongoException, DataAccessException {
- return db.command(command, options);
+ return db.command(command, readPreference);
}
});
@@ -414,14 +431,20 @@ public T execute(String collectionName, CollectionCallback callback) {
}
}
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.mongodb.core.MongoOperations#executeInSession(org.springframework.data.mongodb.core.DbCallback)
+ */
+ @Deprecated
public T executeInSession(final DbCallback action) {
+
return execute(new DbCallback() {
public T doInDB(DB db) throws MongoException, DataAccessException {
try {
- db.requestStart();
+ ReflectiveDbInvoker.requestStart(db);
return action.doInDB(db);
} finally {
- db.requestDone();
+ ReflectiveDbInvoker.requestDone(db);
}
}
});
@@ -699,13 +722,23 @@ protected void prepareCollection(DBCollection collection) {
/**
* Prepare the WriteConcern before any processing is done using it. This allows a convenient way to apply custom
- * settings in sub-classes.
+ * settings in sub-classes.
+ * In case of using mongo-java-driver version 3 the returned {@link WriteConcern} will be defaulted to
+ * {@link WriteConcern#ACKNOWLEDGED} when {@link WriteResultChecking} is set to {@link WriteResultChecking#EXCEPTION}.
*
* @param writeConcern any WriteConcern already configured or null
* @return The prepared WriteConcern or null
*/
protected WriteConcern prepareWriteConcern(MongoAction mongoAction) {
- return writeConcernResolver.resolve(mongoAction);
+
+ WriteConcern wc = writeConcernResolver.resolve(mongoAction);
+
+ if (MongoClientVersion.isMongo3Driver()
+ && ObjectUtils.nullSafeEquals(WriteResultChecking.EXCEPTION, writeResultChecking)
+ && (wc == null || wc.getW() < 1)) {
+ return WriteConcern.ACKNOWLEDGED;
+ }
+ return wc;
}
protected void doInsert(String collectionName, T objectToSave, MongoWriter writer) {
@@ -1026,7 +1059,8 @@ public WriteResult doInCollection(DBCollection collection) throws MongoException
: collection.update(queryObj, updateObj, upsert, multi, writeConcernToUse);
if (entity != null && entity.hasVersionProperty() && !multi) {
- if (writeResult.getN() == 0 && dbObjectContainsVersionProperty(queryObj, entity)) {
+ if (ReflectiveWriteResultInvoker.wasAcknowledged(writeResult) && writeResult.getN() == 0
+ && dbObjectContainsVersionProperty(queryObj, entity)) {
throw new OptimisticLockingFailureException("Optimistic lock exception on saving entity: "
+ updateObj.toMap().toString() + " to collection " + collectionName);
}
@@ -1242,25 +1276,24 @@ public MapReduceResults mapReduce(Query query, String inputCollectionName
String mapFunc = replaceWithResourceIfNecessary(mapFunction);
String reduceFunc = replaceWithResourceIfNecessary(reduceFunction);
DBCollection inputCollection = getCollection(inputCollectionName);
+
MapReduceCommand command = new MapReduceCommand(inputCollection, mapFunc, reduceFunc,
- mapReduceOptions.getOutputCollection(), mapReduceOptions.getOutputType(), null);
+ mapReduceOptions.getOutputCollection(), mapReduceOptions.getOutputType(), query == null
+ || query.getQueryObject() == null ? null : queryMapper.getMappedObject(query.getQueryObject(), null));
- DBObject commandObject = copyQuery(query, copyMapReduceOptions(mapReduceOptions, command));
+ copyMapReduceOptionsToCommand(query, mapReduceOptions, command);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Executing MapReduce on collection [" + command.getInput() + "], mapFunction [" + mapFunc
+ "], reduceFunction [" + reduceFunc + "]");
}
- CommandResult commandResult = command.getOutputType() == MapReduceCommand.OutputType.INLINE ? executeCommand(
- commandObject, getDb().getOptions()) : executeCommand(commandObject);
- handleCommandError(commandResult, commandObject);
+ MapReduceOutput mapReduceOutput = inputCollection.mapReduce(command);
if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("MapReduce command result = [{}]", serializeToJsonSafely(commandObject));
+ LOGGER.debug("MapReduce command result = [{}]", serializeToJsonSafely(mapReduceOutput.results()));
}
- MapReduceOutput mapReduceOutput = new MapReduceOutput(inputCollection, commandObject, commandResult);
List mappedResults = new ArrayList();
DbObjectCallback callback = new ReadDbObjectCallback(mongoConverter, entityClass);
@@ -1268,7 +1301,7 @@ public MapReduceResults mapReduce(Query query, String inputCollectionName
mappedResults.add(callback.doWith(dbObject));
}
- return new MapReduceResults(mappedResults, commandResult);
+ return new MapReduceResults(mappedResults, mapReduceOutput);
}
public GroupByResults group(String inputCollectionName, GroupBy groupBy, Class entityClass) {
@@ -1475,51 +1508,40 @@ protected String replaceWithResourceIfNecessary(String function) {
return func;
}
- private DBObject copyQuery(Query query, DBObject copyMapReduceOptions) {
+ private void copyMapReduceOptionsToCommand(Query query, MapReduceOptions mapReduceOptions,
+ MapReduceCommand mapReduceCommand) {
+
if (query != null) {
if (query.getSkip() != 0 || query.getFieldsObject() != null) {
throw new InvalidDataAccessApiUsageException(
"Can not use skip or field specification with map reduce operations");
}
- if (query.getQueryObject() != null) {
- copyMapReduceOptions.put("query", queryMapper.getMappedObject(query.getQueryObject(), null));
- }
+
if (query.getLimit() > 0) {
- copyMapReduceOptions.put("limit", query.getLimit());
+ mapReduceCommand.setLimit(query.getLimit());
}
if (query.getSortObject() != null) {
- copyMapReduceOptions.put("sort", queryMapper.getMappedObject(query.getSortObject(), null));
+ mapReduceCommand.setSort(queryMapper.getMappedObject(query.getSortObject(), null));
}
}
- return copyMapReduceOptions;
- }
- private DBObject copyMapReduceOptions(MapReduceOptions mapReduceOptions, MapReduceCommand command) {
if (mapReduceOptions.getJavaScriptMode() != null) {
- command.addExtraOption("jsMode", true);
+ mapReduceCommand.setJsMode(true);
}
if (!mapReduceOptions.getExtraOptions().isEmpty()) {
for (Map.Entry entry : mapReduceOptions.getExtraOptions().entrySet()) {
- command.addExtraOption(entry.getKey(), entry.getValue());
+ ReflectiveMapReduceInvoker.addExtraOption(mapReduceCommand, entry.getKey(), entry.getValue());
}
}
if (mapReduceOptions.getFinalizeFunction() != null) {
- command.setFinalize(this.replaceWithResourceIfNecessary(mapReduceOptions.getFinalizeFunction()));
+ mapReduceCommand.setFinalize(this.replaceWithResourceIfNecessary(mapReduceOptions.getFinalizeFunction()));
}
if (mapReduceOptions.getOutputDatabase() != null) {
- command.setOutputDB(mapReduceOptions.getOutputDatabase());
+ mapReduceCommand.setOutputDB(mapReduceOptions.getOutputDatabase());
}
if (!mapReduceOptions.getScopeVariables().isEmpty()) {
- command.setScope(mapReduceOptions.getScopeVariables());
- }
-
- DBObject commandObject = command.toDBObject();
- DBObject outObject = (DBObject) commandObject.get("out");
-
- if (mapReduceOptions.getOutputSharded() != null) {
- outObject.put("sharded", mapReduceOptions.getOutputSharded());
+ mapReduceCommand.setScope(mapReduceOptions.getScopeVariables());
}
- return commandObject;
}
public Set getCollectionNames() {
@@ -1900,7 +1922,7 @@ protected void handleAnyWriteResultErrors(WriteResult writeResult, DBObject quer
return;
}
- String error = writeResult.getError();
+ String error = ReflectiveWriteResultInvoker.getError(writeResult);
if (error == null) {
return;
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReflectiveDBCollectionInvoker.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReflectiveDBCollectionInvoker.java
new file mode 100644
index 0000000000..b814f60b94
--- /dev/null
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReflectiveDBCollectionInvoker.java
@@ -0,0 +1,102 @@
+/*
+ * 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.data.mongodb.core;
+
+import static org.springframework.data.mongodb.MongoClientVersion.*;
+import static org.springframework.util.ReflectionUtils.*;
+
+import java.lang.reflect.Method;
+
+import org.springframework.data.mongodb.MongoClientVersion;
+
+import com.mongodb.DBCollection;
+import com.mongodb.DBObject;
+
+/**
+ * {@link ReflectiveDBCollectionInvoker} provides reflective access to {@link DBCollection} API that is not consistently
+ * available for various driver versions.
+ *
+ * @author Christoph Strobl
+ * @since 1.7
+ */
+class ReflectiveDBCollectionInvoker {
+
+ private static final Method GEN_INDEX_NAME_METHOD;
+ private static final Method RESET_INDEX_CHACHE_METHOD;
+
+ static {
+
+ GEN_INDEX_NAME_METHOD = findMethod(DBCollection.class, "genIndexName", DBObject.class);
+ RESET_INDEX_CHACHE_METHOD = findMethod(DBCollection.class, "resetIndexCache");
+ }
+
+ private ReflectiveDBCollectionInvoker() {}
+
+ /**
+ * Convenience method to generate an index name from the set of fields it is over. Will fall back to a
+ * mongo-java-driver version 2 compatible way of generating index name in case of
+ * {@link MongoClientVersion#isMongo3Driver()}.
+ *
+ * @param keys the names of the fields used in this index
+ * @return
+ */
+ public static String generateIndexName(DBObject keys) {
+
+ if (isMongo3Driver()) {
+ return genIndexName(keys);
+ }
+ return (String) invokeMethod(GEN_INDEX_NAME_METHOD, null, keys);
+ }
+
+ /**
+ * In case of mongo-java-driver version 2 all indices that have not yet been applied to this collection will be
+ * cleared. Since this method is not available for the mongo-java-driver version 3 the operation will throw
+ * {@link UnsupportedOperationException}.
+ *
+ * @param dbCollection
+ * @throws UnsupportedOperationException
+ */
+ public static void resetIndexCache(DBCollection dbCollection) {
+
+ if (isMongo3Driver()) {
+ throw new UnsupportedOperationException("The mongo java driver 3 does no loger support resetIndexCache!");
+ }
+
+ invokeMethod(RESET_INDEX_CHACHE_METHOD, dbCollection);
+ }
+
+ /**
+ * Borrowed from mongo-java-driver version 2. See http://github.com/mongodb/mongo-java-driver/blob/r2.13.0/src/main/com/mongodb/DBCollection.java#L754
+ *
+ * @param keys
+ * @return
+ */
+ private static String genIndexName(DBObject keys) {
+
+ StringBuilder name = new StringBuilder();
+ for (String s : keys.keySet()) {
+ if (name.length() > 0)
+ name.append('_');
+ name.append(s).append('_');
+ Object val = keys.get(s);
+ if (val instanceof Number || val instanceof String)
+ name.append(val.toString().replace(' ', '_'));
+ }
+ return name.toString();
+ }
+}
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReflectiveDbInvoker.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReflectiveDbInvoker.java
new file mode 100644
index 0000000000..600c365ad7
--- /dev/null
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReflectiveDbInvoker.java
@@ -0,0 +1,131 @@
+/*
+ * 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.data.mongodb.core;
+
+import java.lang.reflect.Method;
+
+import org.springframework.data.authentication.UserCredentials;
+import org.springframework.data.mongodb.CannotGetMongoDbConnectionException;
+import org.springframework.data.mongodb.MongoClientVersion;
+import org.springframework.util.ReflectionUtils;
+
+import com.mongodb.DB;
+import com.mongodb.Mongo;
+
+/**
+ * {@link ReflectiveDbInvoker} provides reflective access to {@link DB} API that is not consistently available for
+ * various driver versions.
+ *
+ * @author Christoph Strobl
+ * @since 1.7
+ */
+final class ReflectiveDbInvoker {
+
+ private static final Method DB_IS_AUTHENTICATED_METHOD;
+ private static final Method DB_AUTHENTICATE_METHOD;
+ private static final Method DB_REQUEST_DONE_METHOD;
+ private static final Method DB_ADD_USER_METHOD;
+ private static final Method DB_REQUEST_START_METHOD;
+
+ static {
+
+ DB_IS_AUTHENTICATED_METHOD = ReflectionUtils.findMethod(DB.class, "isAuthenticated");
+ DB_AUTHENTICATE_METHOD = ReflectionUtils.findMethod(DB.class, "authenticate", String.class, char[].class);
+ DB_REQUEST_DONE_METHOD = ReflectionUtils.findMethod(DB.class, "requestDone");
+ DB_ADD_USER_METHOD = ReflectionUtils.findMethod(DB.class, "addUser", String.class, char[].class);
+ DB_REQUEST_START_METHOD = ReflectionUtils.findMethod(DB.class, "requestStart");
+ }
+
+ private ReflectiveDbInvoker() {}
+
+ /**
+ * Authenticate against database using provided credentials in case of a mongo-java-driver version 2.
+ *
+ * @param mongo must not be {@literal null}.
+ * @param db must not be {@literal null}.
+ * @param credentials must not be {@literal null}.
+ * @param authenticationDatabaseName
+ */
+ public static void authenticate(Mongo mongo, DB db, UserCredentials credentials, String authenticationDatabaseName) {
+
+ String databaseName = db.getName();
+
+ DB authDb = databaseName.equals(authenticationDatabaseName) ? db : mongo.getDB(authenticationDatabaseName);
+
+ synchronized (authDb) {
+
+ Boolean isAuthenticated = (Boolean) ReflectionUtils.invokeMethod(DB_IS_AUTHENTICATED_METHOD, authDb);
+ if (!isAuthenticated) {
+
+ String username = credentials.getUsername();
+ String password = credentials.hasPassword() ? credentials.getPassword() : null;
+
+ Boolean authenticated = (Boolean) ReflectionUtils.invokeMethod(DB_AUTHENTICATE_METHOD, authDb, username,
+ password == null ? null : password.toCharArray());
+ if (!authenticated) {
+ throw new CannotGetMongoDbConnectionException("Failed to authenticate to database [" + databaseName + "], "
+ + credentials.toString(), databaseName, credentials);
+ }
+ }
+ }
+ }
+
+ /**
+ * Starts a new 'consistent request' in case of mongo-java-driver version 2. Will do nothing for mongo-java-driver
+ * version 3 since the operation is no longer available.
+ *
+ * @param db
+ */
+ public static void requestStart(DB db) {
+
+ if (MongoClientVersion.isMongo3Driver()) {
+ return;
+ }
+
+ ReflectionUtils.invokeMethod(DB_REQUEST_START_METHOD, db);
+ }
+
+ /**
+ * Ends the current 'consistent request'. a new 'consistent request' in case of mongo-java-driver version 2. Will do
+ * nothing for mongo-java-driver version 3 since the operation is no longer available
+ *
+ * @param db
+ */
+ public static void requestDone(DB db) {
+
+ if (MongoClientVersion.isMongo3Driver()) {
+ return;
+ }
+
+ ReflectionUtils.invokeMethod(DB_REQUEST_DONE_METHOD, db);
+ }
+
+ /**
+ * @param db
+ * @param username
+ * @param password
+ * @throws UnsupportedOperationException
+ */
+ public static void addUser(DB db, String username, char[] password) {
+
+ if (MongoClientVersion.isMongo3Driver()) {
+ throw new UnsupportedOperationException("Please DB.command to call either the createUser or updateUser command");
+ }
+
+ ReflectionUtils.invokeMethod(DB_ADD_USER_METHOD, db, username, password);
+ }
+
+}
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReflectiveMapReduceInvoker.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReflectiveMapReduceInvoker.java
new file mode 100644
index 0000000000..72065909ed
--- /dev/null
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReflectiveMapReduceInvoker.java
@@ -0,0 +1,62 @@
+/*
+ * 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.data.mongodb.core;
+
+import java.lang.reflect.Method;
+
+import org.springframework.data.mongodb.MongoClientVersion;
+import org.springframework.util.Assert;
+import org.springframework.util.ReflectionUtils;
+
+import com.mongodb.MapReduceCommand;
+
+/**
+ * {@link ReflectiveMapReduceInvoker} provides reflective access to {@link MapReduceCommand} API that is not
+ * consistently available for various driver versions.
+ *
+ * @author Christoph Strobl
+ * @since 1.7
+ */
+final class ReflectiveMapReduceInvoker {
+
+ private static final Method ADD_EXTRA_OPTION_METHOD;
+
+ static {
+
+ ADD_EXTRA_OPTION_METHOD = ReflectionUtils.findMethod(MapReduceCommand.class, "addExtraOption", String.class,
+ Object.class);
+ }
+
+ private ReflectiveMapReduceInvoker() {}
+
+ /**
+ * Sets the extra option for mongo-java-driver version 2. Will do nothing for mongo-java-driver version 2.
+ *
+ * @param cmd can be {@literal null} for mongo-java-driver version 2.
+ * @param key
+ * @param value
+ */
+ public static void addExtraOption(MapReduceCommand cmd, String key, Object value) {
+
+ if (MongoClientVersion.isMongo3Driver()) {
+ return;
+ }
+
+ Assert.notNull(cmd, "MapReduceCommand must not be null!");
+ ReflectionUtils.invokeMethod(ADD_EXTRA_OPTION_METHOD, cmd, key, value);
+ }
+
+}
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReflectiveMongoOptionsInvoker.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReflectiveMongoOptionsInvoker.java
new file mode 100644
index 0000000000..f8f4f6b6d0
--- /dev/null
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReflectiveMongoOptionsInvoker.java
@@ -0,0 +1,149 @@
+/*
+ * 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.data.mongodb.core;
+
+import java.lang.reflect.Method;
+
+import org.springframework.beans.DirectFieldAccessor;
+import org.springframework.data.mongodb.MongoClientVersion;
+import org.springframework.util.ReflectionUtils;
+
+import com.mongodb.MongoOptions;
+
+/**
+ * {@link ReflectiveMongoOptionsInvoker} provides reflective access to {@link MongoOptions} API that is not consistently
+ * available for various driver versions.
+ *
+ * @author Christoph Strobl
+ * @since 1.7
+ */
+class ReflectiveMongoOptionsInvoker {
+
+ private static final Method GET_AUTO_CONNECT_RETRY_METHOD;
+ private static final Method SET_AUTO_CONNECT_RETRY_METHOD;
+ private static final Method GET_MAX_AUTO_CONNECT_RETRY_TIME_METHOD;
+ private static final Method SET_MAX_AUTO_CONNECT_RETRY_TIME_METHOD;
+
+ static {
+
+ SET_AUTO_CONNECT_RETRY_METHOD = ReflectionUtils
+ .findMethod(MongoOptions.class, "setAutoConnectRetry", boolean.class);
+ GET_AUTO_CONNECT_RETRY_METHOD = ReflectionUtils.findMethod(MongoOptions.class, "isAutoConnectRetry");
+ SET_MAX_AUTO_CONNECT_RETRY_TIME_METHOD = ReflectionUtils.findMethod(MongoOptions.class,
+ "setMaxAutoConnectRetryTime", long.class);
+ GET_MAX_AUTO_CONNECT_RETRY_TIME_METHOD = ReflectionUtils.findMethod(MongoOptions.class,
+ "getMaxAutoConnectRetryTime");
+ }
+
+ private ReflectiveMongoOptionsInvoker() {}
+
+ /**
+ * Sets the retry connection flag for mongo-java-driver version 2. Will do nothing for mongo-java-driver version 3
+ * since the method has been removed.
+ *
+ * @param options can be {@literal null} for mongo-java-driver version 3.
+ * @param autoConnectRetry
+ */
+ public static void setAutoConnectRetry(MongoOptions options, boolean autoConnectRetry) {
+
+ if (MongoClientVersion.isMongo3Driver()) {
+ return;
+ }
+ ReflectionUtils.invokeMethod(SET_AUTO_CONNECT_RETRY_METHOD, options, autoConnectRetry);
+ }
+
+ /**
+ * Sets the maxAutoConnectRetryTime attribute for mongo-java-driver version 2. Will do nothing for mongo-java-driver
+ * version 3 since the method has been removed.
+ *
+ * @param options can be {@literal null} for mongo-java-driver version 3.
+ * @param maxAutoConnectRetryTime
+ */
+ public static void setMaxAutoConnectRetryTime(MongoOptions options, long maxAutoConnectRetryTime) {
+
+ if (MongoClientVersion.isMongo3Driver()) {
+ return;
+ }
+ ReflectionUtils.invokeMethod(SET_MAX_AUTO_CONNECT_RETRY_TIME_METHOD, options, maxAutoConnectRetryTime);
+ }
+
+ /**
+ * Sets the slaveOk attribute for mongo-java-driver version 2. Will do nothing for mongo-java-driver version 3 since
+ * the method has been removed.
+ *
+ * @param options can be {@literal null} for mongo-java-driver version 3.
+ * @param slaveOk
+ */
+ public static void setSlaveOk(MongoOptions options, boolean slaveOk) {
+
+ if (MongoClientVersion.isMongo3Driver()) {
+ return;
+ }
+ new DirectFieldAccessor(options).setPropertyValue("slaveOk", slaveOk);
+ }
+
+ /**
+ * Gets the slaveOk attribute for mongo-java-driver version 2. Throws {@link UnsupportedOperationException} for
+ * mongo-java-driver version 3 since the method has been removed.
+ *
+ * @param options can be {@literal null} for mongo-java-driver version 3.
+ * @return
+ * @throws UnsupportedOperationException
+ */
+ public static boolean getSlaveOk(MongoOptions options) {
+
+ if (MongoClientVersion.isMongo3Driver()) {
+ throw new UnsupportedOperationException(
+ "Cannot get value for autoConnectRetry which has been removed in mongo-java-driver version 3.");
+ }
+ return ((Boolean) new DirectFieldAccessor(options).getPropertyValue("slaveOk")).booleanValue();
+ }
+
+ /**
+ * Gets the autoConnectRetry attribute for mongo-java-driver version 2. Throws {@link UnsupportedOperationException}
+ * for mongo-java-driver version 3 since the method has been removed.
+ *
+ * @param options can be {@literal null} for mongo-java-driver version 3.
+ * @return
+ * @throws UnsupportedOperationException
+ */
+ public static boolean getAutoConnectRetry(MongoOptions options) {
+
+ if (MongoClientVersion.isMongo3Driver()) {
+ throw new UnsupportedOperationException(
+ "Cannot get value for autoConnectRetry which has been removed in mongo-java-driver version 3.");
+ }
+ return ((Boolean) ReflectionUtils.invokeMethod(GET_AUTO_CONNECT_RETRY_METHOD, options)).booleanValue();
+ }
+
+ /**
+ * Gets the maxAutoConnectRetryTime attribute for mongo-java-driver version 2. Throws
+ * {@link UnsupportedOperationException} for mongo-java-driver version 3 since the method has been removed.
+ *
+ * @param options can be {@literal null} for mongo-java-driver version 3.
+ * @return
+ * @throws UnsupportedOperationException
+ */
+ public static long getMaxAutoConnectRetryTime(MongoOptions options) {
+
+ if (MongoClientVersion.isMongo3Driver()) {
+ throw new UnsupportedOperationException(
+ "Cannot get value for maxAutoConnectRetryTime which has been removed in mongo-java-driver version 3.");
+ }
+
+ return ((Long) ReflectionUtils.invokeMethod(GET_MAX_AUTO_CONNECT_RETRY_TIME_METHOD, options)).longValue();
+ }
+}
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReflectiveWriteConcernInvoker.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReflectiveWriteConcernInvoker.java
new file mode 100644
index 0000000000..8f3be853b7
--- /dev/null
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReflectiveWriteConcernInvoker.java
@@ -0,0 +1,46 @@
+/*
+ * 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.data.mongodb.core;
+
+import org.springframework.beans.DirectFieldAccessor;
+import org.springframework.data.mongodb.MongoClientVersion;
+
+import com.mongodb.WriteConcern;
+
+/**
+ * {@link ReflectiveWriteConcernInvoker} provides reflective access to {@link WriteConcern} API that is not consistently
+ * available for various driver versions.
+ *
+ * @author Christoph Strobl
+ * @since 1.7
+ */
+class ReflectiveWriteConcernInvoker {
+
+ private static final WriteConcern NONE_OR_UNACKNOWLEDGED;
+
+ static {
+
+ NONE_OR_UNACKNOWLEDGED = MongoClientVersion.isMongo3Driver() ? WriteConcern.UNACKNOWLEDGED
+ : (WriteConcern) new DirectFieldAccessor(new WriteConcern()).getPropertyValue("NONE");
+ }
+
+ /**
+ * @return {@link WriteConcern#NONE} for mongo-java-driver version 2, otherwise {@link WriteConcern#UNACKNOWLEDGED}.
+ */
+ public static WriteConcern noneOrUnacknowledged() {
+ return NONE_OR_UNACKNOWLEDGED;
+ }
+}
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReflectiveWriteResultInvoker.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReflectiveWriteResultInvoker.java
new file mode 100644
index 0000000000..224e649e0e
--- /dev/null
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReflectiveWriteResultInvoker.java
@@ -0,0 +1,70 @@
+/*
+ * 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.data.mongodb.core;
+
+import static org.springframework.util.ReflectionUtils.*;
+
+import java.lang.reflect.Method;
+
+import org.springframework.data.mongodb.MongoClientVersion;
+import org.springframework.util.ReflectionUtils;
+
+import com.mongodb.MongoException;
+import com.mongodb.WriteResult;
+
+/**
+ * {@link ReflectiveWriteResultInvoker} provides reflective access to {@link WriteResult} API that is not consistently
+ * available for various driver versions.
+ *
+ * @author Christoph Strobl
+ * @since 1.7
+ */
+final class ReflectiveWriteResultInvoker {
+
+ private static final Method GET_ERROR_METHOD;
+ private static final Method WAS_ACKNOWLEDGED_METHOD;
+
+ private ReflectiveWriteResultInvoker() {}
+
+ static {
+
+ GET_ERROR_METHOD = findMethod(WriteResult.class, "getError");
+ WAS_ACKNOWLEDGED_METHOD = findMethod(WriteResult.class, "wasAcknowledged");
+ }
+
+ /**
+ * @param writeResult can be {@literal null} for mongo-java-driver version 3.
+ * @return null in case of mongo-java-driver version 3 since errors are thrown as {@link MongoException}.
+ */
+ public static String getError(WriteResult writeResult) {
+
+ if (MongoClientVersion.isMongo3Driver()) {
+ return null;
+ }
+
+ return (String) invokeMethod(GET_ERROR_METHOD, writeResult);
+ }
+
+ /**
+ * @param writeResult
+ * @return return in case of mongo-java-driver version 2.
+ */
+ public static boolean wasAcknowledged(WriteResult writeResult) {
+ return MongoClientVersion.isMongo3Driver() ? ((Boolean) ReflectionUtils.invokeMethod(WAS_ACKNOWLEDGED_METHOD,
+ writeResult)).booleanValue() : true;
+ }
+
+}
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/SimpleMongoDbFactory.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/SimpleMongoDbFactory.java
index 0a9d8e4b78..0ca28a29ac 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/SimpleMongoDbFactory.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/SimpleMongoDbFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2013 the original author or authors.
+ * Copyright 2011-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.
@@ -27,6 +27,8 @@
import com.mongodb.DB;
import com.mongodb.Mongo;
+import com.mongodb.MongoClient;
+import com.mongodb.MongoClientURI;
import com.mongodb.MongoException;
import com.mongodb.MongoURI;
import com.mongodb.WriteConcern;
@@ -37,6 +39,7 @@
* @author Mark Pollack
* @author Oliver Gierke
* @author Thomas Darimont
+ * @author Christoph Strobl
*/
public class SimpleMongoDbFactory implements DisposableBean, MongoDbFactory {
@@ -54,7 +57,9 @@ public class SimpleMongoDbFactory implements DisposableBean, MongoDbFactory {
*
* @param mongo Mongo instance, must not be {@literal null}.
* @param databaseName database name, not be {@literal null} or empty.
+ * @deprecated since 1.7. Please use {@link #SimpleMongoDbFactory(MongoClient, String)}.
*/
+ @Deprecated
public SimpleMongoDbFactory(Mongo mongo, String databaseName) {
this(mongo, databaseName, null);
}
@@ -65,7 +70,9 @@ public SimpleMongoDbFactory(Mongo mongo, String databaseName) {
* @param mongo Mongo instance, must not be {@literal null}.
* @param databaseName Database name, must not be {@literal null} or empty.
* @param credentials username and password.
+ * @deprecated since 1.7. The credentials used should be provided by {@link MongoClient#getCredentialsList()}.
*/
+ @Deprecated
public SimpleMongoDbFactory(Mongo mongo, String databaseName, UserCredentials credentials) {
this(mongo, databaseName, credentials, false, null);
}
@@ -77,7 +84,9 @@ public SimpleMongoDbFactory(Mongo mongo, String databaseName, UserCredentials cr
* @param databaseName Database name, must not be {@literal null} or empty.
* @param credentials username and password.
* @param authenticationDatabaseName the database name to use for authentication
+ * @deprecated since 1.7. The credentials used should be provided by {@link MongoClient#getCredentialsList()}.
*/
+ @Deprecated
public SimpleMongoDbFactory(Mongo mongo, String databaseName, UserCredentials credentials,
String authenticationDatabaseName) {
this(mongo, databaseName, credentials, false, authenticationDatabaseName);
@@ -90,13 +99,36 @@ public SimpleMongoDbFactory(Mongo mongo, String databaseName, UserCredentials cr
* @throws MongoException
* @throws UnknownHostException
* @see MongoURI
+ * @deprecated since 1.7. Please use {@link #SimpleMongoDbFactory(MongoClientURI)} instead.
*/
- @SuppressWarnings("deprecation")
+ @Deprecated
public SimpleMongoDbFactory(MongoURI uri) throws MongoException, UnknownHostException {
this(new Mongo(uri), uri.getDatabase(), new UserCredentials(uri.getUsername(), parseChars(uri.getPassword())),
true, uri.getDatabase());
}
+ /**
+ * Creates a new {@link SimpleMongoDbFactory} instance from the given {@link MongoClientURI}.
+ *
+ * @param uri must not be {@literal null}.
+ * @throws UnknownHostException
+ * @since 1.7
+ */
+ public SimpleMongoDbFactory(MongoClientURI uri) throws UnknownHostException {
+ this(new MongoClient(uri), uri.getDatabase(), true);
+ }
+
+ /**
+ * Creates a new {@link SimpleMongoDbFactory} instance from the given {@link MongoClient}.
+ *
+ * @param mongoClient must not be {@literal null}.
+ * @param databaseName must not be {@literal null}.
+ * @since 1.7
+ */
+ public SimpleMongoDbFactory(MongoClient mongoClient, String databaseName) {
+ this(mongoClient, databaseName, false);
+ }
+
private SimpleMongoDbFactory(Mongo mongo, String databaseName, UserCredentials credentials,
boolean mongoInstanceCreated, String authenticationDatabaseName) {
@@ -117,6 +149,25 @@ private SimpleMongoDbFactory(Mongo mongo, String databaseName, UserCredentials c
"Authentication database name must only contain letters, numbers, underscores and dashes!");
}
+ /**
+ * @param client
+ * @param databaseName
+ * @param mongoInstanceCreated
+ * @since 1.7
+ */
+ private SimpleMongoDbFactory(MongoClient client, String databaseName, boolean mongoInstanceCreated) {
+
+ Assert.notNull(client, "MongoClient must not be null!");
+ Assert.hasText(databaseName, "Database name must not be empty!");
+
+ this.mongo = client;
+ this.databaseName = databaseName;
+ this.mongoInstanceCreated = mongoInstanceCreated;
+ this.exceptionTranslator = new MongoExceptionTranslator();
+ this.credentials = UserCredentials.NO_CREDENTIALS;
+ this.authenticationDatabaseName = databaseName;
+ }
+
/**
* Configures the {@link WriteConcern} to be used on the {@link DB} instance being created.
*
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DbRefResolver.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DbRefResolver.java
index 47910299b5..a43b742c6d 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DbRefResolver.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DbRefResolver.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2014 the original author or authors.
+ * Copyright 2013-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.
@@ -18,6 +18,7 @@
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
+import com.mongodb.DBObject;
import com.mongodb.DBRef;
/**
@@ -25,6 +26,7 @@
*
* @author Thomas Darimont
* @author Oliver Gierke
+ * @author Christoph Strobl
* @since 1.4
*/
public interface DbRefResolver {
@@ -53,4 +55,13 @@ Object resolveDbRef(MongoPersistentProperty property, DBRef dbref, DbRefResolver
*/
DBRef createDbRef(org.springframework.data.mongodb.core.mapping.DBRef annotation, MongoPersistentEntity> entity,
Object id);
+
+ /**
+ * Actually loads the {@link DBRef} from the datasource.
+ *
+ * @param dbRef must not be {@literal null}.
+ * @return
+ * @since 1.7
+ */
+ DBObject fetch(DBRef dbRef);
}
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DefaultDbRefResolver.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DefaultDbRefResolver.java
index 8b64c7cb97..ddea7ff5c9 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DefaultDbRefResolver.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DefaultDbRefResolver.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2014 the original author or authors.
+ * Copyright 2013-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.
@@ -39,9 +39,8 @@
import org.springframework.objenesis.ObjenesisStd;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
-import org.springframework.util.StringUtils;
-import com.mongodb.DB;
+import com.mongodb.DBObject;
import com.mongodb.DBRef;
/**
@@ -50,6 +49,7 @@
*
* @author Thomas Darimont
* @author Oliver Gierke
+ * @author Christoph Strobl
* @since 1.4
*/
public class DefaultDbRefResolver implements DbRefResolver {
@@ -97,11 +97,16 @@ public Object resolveDbRef(MongoPersistentProperty property, DBRef dbref, DbRefR
@Override
public DBRef createDbRef(org.springframework.data.mongodb.core.mapping.DBRef annotation,
MongoPersistentEntity> entity, Object id) {
+ return new DBRef(entity.getCollection(), id);
+ }
- DB db = mongoDbFactory.getDb();
- db = annotation != null && StringUtils.hasText(annotation.db()) ? mongoDbFactory.getDb(annotation.db()) : db;
-
- return new DBRef(db, entity.getCollection(), id);
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.mongodb.core.convert.DbRefResolver#fetch(com.mongodb.DBRef)
+ */
+ @Override
+ public DBObject fetch(DBRef dbRef) {
+ return ReflectiveDBRefResolver.fetch(mongoDbFactory.getDb(), dbRef);
}
/**
@@ -282,7 +287,7 @@ private String proxyToString(Object proxy) {
StringBuilder description = new StringBuilder();
if (dbref != null) {
- description.append(dbref.getRef());
+ description.append(dbref.getCollectionName());
description.append(":");
description.append(dbref.getId());
} else {
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java
index d3aa3ba6f4..94c8bada45 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2014 by the original author(s).
+ * Copyright 2011-2015 by the original author(s).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -1176,7 +1176,7 @@ private T potentiallyReadOrResolveDbRef(DBRef dbref, TypeInformation> type
return (T) dbref;
}
- Object object = dbref == null ? null : path.getPathItem(dbref.getId(), dbref.getRef());
+ Object object = dbref == null ? null : path.getPathItem(dbref.getId(), dbref.getCollectionName());
if (object != null) {
return (T) object;
@@ -1192,6 +1192,6 @@ private T potentiallyReadOrResolveDbRef(DBRef dbref, TypeInformation> type
* @return
*/
DBObject readRef(DBRef ref) {
- return ref.fetch();
+ return dbRefResolver.fetch(ref);
}
}
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java
index 661f6940bf..82a97e2d5b 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2014 the original author or authors.
+ * Copyright 2011-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.
@@ -390,7 +390,7 @@ protected Object convertAssociation(Object source, MongoPersistentProperty prope
if (source instanceof DBRef) {
DBRef ref = (DBRef) source;
- return new DBRef(ref.getDB(), ref.getRef(), convertId(ref.getId()));
+ return new DBRef(ref.getCollectionName(), convertId(ref.getId()));
}
if (source instanceof Iterable) {
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/ReflectiveDBRefResolver.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/ReflectiveDBRefResolver.java
new file mode 100644
index 0000000000..8b83275153
--- /dev/null
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/ReflectiveDBRefResolver.java
@@ -0,0 +1,66 @@
+/*
+ * 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.data.mongodb.core.convert;
+
+import static org.springframework.util.ReflectionUtils.*;
+
+import java.lang.reflect.Method;
+
+import org.springframework.data.mongodb.MongoClientVersion;
+import org.springframework.util.Assert;
+import org.springframework.util.ReflectionUtils;
+
+import com.mongodb.DB;
+import com.mongodb.DBCollection;
+import com.mongodb.DBObject;
+import com.mongodb.DBRef;
+
+/**
+ * {@link ReflectiveDBRefResolver} provides reflective access to {@link DBRef} API that is not consistently available
+ * for various driver versions.
+ *
+ * @author Christoph Strobl
+ * @since 1.7
+ */
+class ReflectiveDBRefResolver {
+
+ private static final Method FETCH_METHOD;
+
+ static {
+
+ FETCH_METHOD = findMethod(DBRef.class, "fetch");
+ }
+
+ /**
+ * Fetches the object referenced from the database either be directly calling {@link DBRef#fetch()} or
+ * {@link DBCollection#findOne(Object)}.
+ *
+ * @param db can be {@literal null} when using mongo-java-driver version 2.
+ * @param ref must not be {@literal null}.
+ * @return the document that this references.
+ */
+ public static DBObject fetch(DB db, DBRef ref) {
+
+ Assert.notNull(ref, "DBRef to fetch must not be null!");
+
+ if (MongoClientVersion.isMongo3Driver()) {
+ return db.getCollection(ref.getCollectionName()).findOne(ref.getId());
+ }
+
+ return (DBObject) ReflectionUtils.invokeMethod(FETCH_METHOD, ref);
+ }
+
+}
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/CompoundIndex.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/CompoundIndex.java
index 2b1807607b..9e5c4a088a 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/CompoundIndex.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/CompoundIndex.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2013 the original author or authors.
+ * Copyright 2011-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.
@@ -28,6 +28,7 @@
* @author Oliver Gierke
* @author Philipp Schneider
* @author Johno Crawford
+ * @author Christoph Strobl
*/
@Target({ ElementType.TYPE })
@Documented
@@ -105,9 +106,9 @@
*
*
*
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/GeoSpatialIndexed.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/GeoSpatialIndexed.java
index 0f13634ff1..119066877e 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/GeoSpatialIndexed.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/GeoSpatialIndexed.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2010-2014 the original author or authors.
+ * Copyright 2010-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.
@@ -26,6 +26,7 @@
* @author Jon Brisbin
* @author Laurent Canet
* @author Thomas Darimont
+ * @author Christoph Strobl
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@@ -62,9 +63,9 @@
*
*
*
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/Indexed.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/Indexed.java
index 58f7c65b62..31eb1ef177 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/Indexed.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/Indexed.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2014 the original author or authors.
+ * Copyright 2011-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.
@@ -28,6 +28,7 @@
* @author Philipp Schneider
* @author Johno Crawford
* @author Thomas Darimont
+ * @author Christoph Strobl
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@@ -88,9 +89,9 @@
*
*