+ *
+ * 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 com.massivecraft.mcore.xlib.mongodb;
+
+/**
+ * A standard MBean interface for a Mongo connection pool, for use on Java 5 virtual machines.
+ *
+ * This interface is NOT part of the public API. Be prepared for non-binary compatible changes in minor releases.
+ */
+public interface Java5MongoConnectionPoolMBean {
+ /**
+ * Gets the name of the pool.
+ *
+ * @return the name of the pool
+ */
+ String getName();
+
+ /**
+ * Gets the host that this connection pool is connecting to.
+ *
+ * @return the host
+ */
+ String getHost();
+
+ /**
+ * Gets the port that this connection pool is connecting to.
+ *
+ * @return the port
+ */
+ int getPort();
+
+ /**
+ * Gets the total number of pool members, including idle and and in-use members.
+ *
+ * @return total number of members
+ */
+ int getTotal();
+
+ /**
+ * Gets the number of pool members that are currently in use.
+ *
+ * @return number of in-use members
+ */
+ int getInUse();
+
+ /**
+ * Gets the maximum allowed size of the pool, including idle and in-use members.
+ *
+ * @return the maximum size
+ */
+ int getMaxSize();
+}
diff --git a/src/com/massivecraft/mcore/xlib/mongodb/LazyDBCallback.java b/src/com/massivecraft/mcore/xlib/mongodb/LazyDBCallback.java
index beaeeed3..d5f139db 100644
--- a/src/com/massivecraft/mcore/xlib/mongodb/LazyDBCallback.java
+++ b/src/com/massivecraft/mcore/xlib/mongodb/LazyDBCallback.java
@@ -24,6 +24,7 @@ import com.massivecraft.mcore.xlib.bson.types.ObjectId;
/**
*
*/
+@SuppressWarnings({"rawtypes", "unused"})
public class LazyDBCallback extends LazyBSONCallback implements DBCallback {
public LazyDBCallback( DBCollection coll ){
@@ -31,8 +32,7 @@ public class LazyDBCallback extends LazyBSONCallback implements DBCallback {
_db = _collection == null ? null : _collection.getDB();
}
- @SuppressWarnings("rawtypes")
- @Override
+ @Override
public Object createObject( byte[] data, int offset ){
LazyDBObject o = new LazyDBObject( data, offset, this );
//log.info("Created inner BSONObject: " + o);
@@ -52,6 +52,5 @@ public class LazyDBCallback extends LazyBSONCallback implements DBCallback {
final DBCollection _collection;
final DB _db;
- @SuppressWarnings("unused")
- private static final Logger log = Logger.getLogger( LazyDBCallback.class.getName() );
+ private static final Logger log = Logger.getLogger( LazyDBCallback.class.getName() );
}
diff --git a/src/com/massivecraft/mcore/xlib/mongodb/LazyDBEncoder.java b/src/com/massivecraft/mcore/xlib/mongodb/LazyDBEncoder.java
index 1c9d9124..245f7d55 100644
--- a/src/com/massivecraft/mcore/xlib/mongodb/LazyDBEncoder.java
+++ b/src/com/massivecraft/mcore/xlib/mongodb/LazyDBEncoder.java
@@ -25,6 +25,13 @@ import java.io.IOException;
* Encoder that only knows how to encode BSONObject instances of type LazyDBObject.
*/
public class LazyDBEncoder implements DBEncoder {
+
+ /**
+ * @param buf
+ * @param o
+ * @return
+ * @throws MongoException
+ */
@Override
public int writeObject(final OutputBuffer buf, BSONObject o) {
if (!(o instanceof LazyDBObject)) {
diff --git a/src/com/massivecraft/mcore/xlib/mongodb/LazyWriteableDBCallback.java b/src/com/massivecraft/mcore/xlib/mongodb/LazyWriteableDBCallback.java
index ae1bf2e0..dba5aa6e 100644
--- a/src/com/massivecraft/mcore/xlib/mongodb/LazyWriteableDBCallback.java
+++ b/src/com/massivecraft/mcore/xlib/mongodb/LazyWriteableDBCallback.java
@@ -21,14 +21,14 @@ import java.util.logging.Logger;
/**
*
*/
+@SuppressWarnings({"rawtypes", "unused"})
public class LazyWriteableDBCallback extends LazyDBCallback {
public LazyWriteableDBCallback( DBCollection coll ){
super(coll);
}
- @SuppressWarnings("rawtypes")
- @Override
+ @Override
public Object createObject( byte[] data, int offset ){
LazyWriteableDBObject o = new LazyWriteableDBObject( data, offset, this );
//log.info("Created inner BSONObject: " + o);
@@ -42,6 +42,5 @@ public class LazyWriteableDBCallback extends LazyDBCallback {
return o;
}
- @SuppressWarnings("unused")
- private static final Logger log = Logger.getLogger( LazyWriteableDBCallback.class.getName() );
+ private static final Logger log = Logger.getLogger( LazyWriteableDBCallback.class.getName() );
}
diff --git a/src/com/massivecraft/mcore/xlib/mongodb/LazyWriteableDBObject.java b/src/com/massivecraft/mcore/xlib/mongodb/LazyWriteableDBObject.java
index 426af2ad..e8eda191 100644
--- a/src/com/massivecraft/mcore/xlib/mongodb/LazyWriteableDBObject.java
+++ b/src/com/massivecraft/mcore/xlib/mongodb/LazyWriteableDBObject.java
@@ -24,6 +24,7 @@ import com.massivecraft.mcore.xlib.bson.BSONObject;
import com.massivecraft.mcore.xlib.bson.LazyBSONCallback;
import com.massivecraft.mcore.xlib.bson.io.BSONByteBuffer;
+@SuppressWarnings({"unchecked", "rawtypes"})
public class LazyWriteableDBObject extends LazyDBObject {
public LazyWriteableDBObject(BSONByteBuffer buff, LazyBSONCallback cbk){
@@ -64,7 +65,6 @@ public class LazyWriteableDBObject extends LazyDBObject {
/* (non-Javadoc)
* @see org.bson.LazyBSONObject#putAll(java.util.Map)
*/
- @SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public void putAll(Map m) {
writeable.putAll(m);
diff --git a/src/com/massivecraft/mcore/xlib/mongodb/MapReduceCommand.java b/src/com/massivecraft/mcore/xlib/mongodb/MapReduceCommand.java
index b12ddaae..1a61ec1d 100644
--- a/src/com/massivecraft/mcore/xlib/mongodb/MapReduceCommand.java
+++ b/src/com/massivecraft/mcore/xlib/mongodb/MapReduceCommand.java
@@ -52,10 +52,9 @@ public class MapReduceCommand {
* @param query
* the query to use on input
* @return
- * @throws MongoException
* @dochub mapreduce
*/
- public MapReduceCommand(DBCollection inputCollection , String map , String reduce , String outputCollection, OutputType type, DBObject query) throws MongoException {
+ public MapReduceCommand(DBCollection inputCollection , String map , String reduce , String outputCollection, OutputType type, DBObject query) {
_input = inputCollection.getName();
_map = map;
_reduce = reduce;
diff --git a/src/com/massivecraft/mcore/xlib/mongodb/MapReduceOutput.java b/src/com/massivecraft/mcore/xlib/mongodb/MapReduceOutput.java
index 0c169fe5..c20aefb6 100644
--- a/src/com/massivecraft/mcore/xlib/mongodb/MapReduceOutput.java
+++ b/src/com/massivecraft/mcore/xlib/mongodb/MapReduceOutput.java
@@ -65,6 +65,7 @@ public class MapReduceOutput {
/**
* drops the collection that holds the results
+ * @throws MongoException
*/
public void drop(){
if ( _coll != null)
diff --git a/src/com/massivecraft/mcore/xlib/mongodb/Mongo.java b/src/com/massivecraft/mcore/xlib/mongodb/Mongo.java
index 2989da70..fc11738f 100644
--- a/src/com/massivecraft/mcore/xlib/mongodb/Mongo.java
+++ b/src/com/massivecraft/mcore/xlib/mongodb/Mongo.java
@@ -18,6 +18,8 @@
package com.massivecraft.mcore.xlib.mongodb;
+import com.massivecraft.mcore.xlib.bson.io.PoolOutputBuffer;
+
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
@@ -25,54 +27,56 @@ import java.util.Collection;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
-
-import com.massivecraft.mcore.xlib.bson.io.PoolOutputBuffer;
+import java.util.logging.Logger;
/**
- * A database connection with internal pooling.
- * For most application, you should have 1 Mongo instance for the entire JVM.
- *
- * The following are equivalent, and all connect to the
- * local database running on the default port:
- *
- *
- * Mongo mongo1 = new Mongo( "127.0.0.1" );
- * Mongo mongo2 = new Mongo( "127.0.0.1", 27017 );
- * Mongo mongo3 = new Mongo( new DBAddress( "127.0.0.1", 27017, "test" ) );
- * Mongo mongo4 = new Mongo( new ServerAddress( "127.0.0.1") );
- *
- *
- * Mongo instances have connection pooling built in - see the requestStart
- * and requestDone methods for more information.
- * http://www.mongodb.org/display/DOCS/Java+Driver+Concurrency
- *
- * Connecting to a Replica Set
+ * A database connection with internal connection pooling. For most applications, you should have one Mongo instance
+ * for the entire JVM.
+ *
+ * The following are equivalent, and all connect to the local database running on the default port:
+ *
+ * Mongo mongo1 = new Mongo();
+ * Mongo mongo1 = new Mongo("localhost");
+ * Mongo mongo2 = new Mongo("localhost", 27017);
+ * Mongo mongo4 = new Mongo(new ServerAddress("localhost"));
+ *
*
* You can connect to a
- * replica set
- * using the Java driver by passing several a list if ServerAddress to the
- * Mongo constructor.
- * For example:
- *
- *
- * List addrs = new ArrayList();
- * addrs.add( new ServerAddress( "127.0.0.1" , 27017 ) );
- * addrs.add( new ServerAddress( "127.0.0.1" , 27018 ) );
- * addrs.add( new ServerAddress( "127.0.0.1" , 27019 ) );
- *
- * Mongo mongo = new Mongo( addrs );
- *
- *
+ * replica set using the Java driver by passing
+ * a ServerAddress list to the Mongo constructor. For example:
+ *
+ * Mongo mongo = new Mongo(Arrays.asList(
+ * new ServerAddress("localhost", 27017),
+ * new ServerAddress("localhost", 27018),
+ * new ServerAddress("localhost", 27019)));
+ *
+ * You can connect to a sharded cluster using the same constructor. Mongo will auto-detect whether the servers are
+ * a list of replica set members or a list of mongos servers.
*
- * By default, all read and write operations will be made on the master.
- * But it's possible to read from the slave(s) by using slaveOk:
- *
- *
- * mongo.slaveOk();
- *
+ * By default, all read and write operations will be made on the primary,
+ * but it's possible to read from secondaries by changing the read preference:
+ *
+ *
+ * mongo.setReadPreference(ReadPreference.secondary());
+ *
+ * By default, write operations will not throw exceptions on failure, but that is easily changed too:
+ *
+ *
+ * mongo.setWriteConcern(WriteConcern.SAFE);
+ *
+ *
+ * Note: This class has been superseded by {@code MongoClient}, and may be deprecated in a future release.
+ *
+ * @see MongoClient
+ * @see ReadPreference
+ * @see WriteConcern
*/
+@SuppressWarnings({"rawtypes"})
public class Mongo {
+ static Logger logger = Logger.getLogger(Bytes.LOGGER.getName() + ".Mongo");
+
+
// Make sure you don't change the format of these two static variables. A preprocessing regexp
// is applied and updates the version based on configuration in build.properties.
@@ -86,11 +90,14 @@ public class Mongo {
* @deprecated Replaced by Mongo.getMinorVersion()
*/
@Deprecated
- public static final int MINOR_VERSION = 8;
+ public static final int MINOR_VERSION = 11;
- private static final String FULL_VERSION = "2.8.0";
+ private static final String FULL_VERSION = "2.11.1";
static int cleanerIntervalMS;
+
+ private static final String ADMIN_DATABASE_NAME = "admin";
+
static {
cleanerIntervalMS = Integer.parseInt(System.getProperty("com.mongodb.cleanerIntervalMS", "1000"));
}
@@ -115,6 +122,7 @@ public class Mongo {
* returns a database object
* @param addr the database address
* @return
+ * @throws MongoException
*/
public static DB connect( DBAddress addr ){
return new Mongo( addr ).getDB( addr.getDBName() );
@@ -124,9 +132,13 @@ public class Mongo {
* Creates a Mongo instance based on a (single) mongodb node (localhost, default port)
* @throws UnknownHostException
* @throws MongoException
+ *
+ * @deprecated Replaced by {@link MongoClient#MongoClient()})
+ *
*/
+ @Deprecated
public Mongo()
- throws UnknownHostException , MongoException {
+ throws UnknownHostException {
this( new ServerAddress() );
}
@@ -135,9 +147,13 @@ public class Mongo {
* @param host server to connect to
* @throws UnknownHostException if the database host cannot be resolved
* @throws MongoException
+ *
+ * @deprecated Replaced by {@link MongoClient#MongoClient(String)}
+ *
*/
+ @Deprecated
public Mongo( String host )
- throws UnknownHostException , MongoException {
+ throws UnknownHostException{
this( new ServerAddress( host ) );
}
@@ -147,9 +163,13 @@ public class Mongo {
* @param options default query options
* @throws UnknownHostException if the database host cannot be resolved
* @throws MongoException
+ *
+ * @deprecated Replaced by {@link MongoClient#MongoClient(String, MongoClientOptions)}
+ *
*/
+ @Deprecated
public Mongo( String host , MongoOptions options )
- throws UnknownHostException , MongoException {
+ throws UnknownHostException {
this( new ServerAddress( host ) , options );
}
@@ -159,9 +179,13 @@ public class Mongo {
* @param port the port on which the database is running
* @throws UnknownHostException if the database host cannot be resolved
* @throws MongoException
+ *
+ * @deprecated Replaced by {@link MongoClient#MongoClient(String, int)}
+ *
*/
+ @Deprecated
public Mongo( String host , int port )
- throws UnknownHostException , MongoException {
+ throws UnknownHostException {
this( new ServerAddress( host , port ) );
}
@@ -170,10 +194,13 @@ public class Mongo {
* @see com.massivecraft.mcore.xlib.mongodb.ServerAddress
* @param addr the database address
* @throws MongoException
+ *
+ * @deprecated Replaced by {@link MongoClient#MongoClient(ServerAddress)}
+ *
*/
- public Mongo( ServerAddress addr )
- throws MongoException {
- this( addr , new MongoOptions() );
+ @Deprecated
+ public Mongo( ServerAddress addr ) {
+ this(addr, new MongoOptions());
}
/**
@@ -182,17 +209,13 @@ public class Mongo {
* @param addr the database address
* @param options default query options
* @throws MongoException
+ *
+ * @deprecated Replaced by {@link MongoClient#MongoClient(ServerAddress, MongoClientOptions)}
+ *
*/
- public Mongo( ServerAddress addr , MongoOptions options )
- throws MongoException {
- _addr = addr;
- _addrs = null;
- _options = options;
- _applyMongoOptions();
- _connector = new DBTCPConnector( this , _addr );
- _connector.start();
- _cleaner = new DBCleanerThread();
- _cleaner.start();
+ @Deprecated
+ public Mongo( ServerAddress addr , MongoOptions options ) {
+ this(MongoAuthority.direct(addr), options);
}
/**
@@ -206,9 +229,8 @@ public class Mongo {
* @throws MongoException
*/
@Deprecated
- public Mongo( ServerAddress left , ServerAddress right )
- throws MongoException {
- this( left , right , new MongoOptions() );
+ public Mongo( ServerAddress left , ServerAddress right ) {
+ this(left, right, new MongoOptions());
}
/**
@@ -223,94 +245,103 @@ public class Mongo {
* @throws MongoException
*/
@Deprecated
- public Mongo( ServerAddress left , ServerAddress right , MongoOptions options )
- throws MongoException {
- _addr = null;
- _addrs = Arrays.asList( left , right );
- _options = options;
- _applyMongoOptions();
- _connector = new DBTCPConnector( this , _addrs );
- _connector.start();
-
- _cleaner = new DBCleanerThread();
- _cleaner.start();
+ public Mongo( ServerAddress left , ServerAddress right , MongoOptions options ) {
+ this(MongoAuthority.dynamicSet(Arrays.asList(left, right)), options);
}
/**
- * Creates a Mongo based on a replica set, or pair.
+ * Creates a Mongo based on a list of replica set members or a list of mongos.
* It will find all members (the master will be used by default). If you pass in a single server in the list,
* the driver will still function as if it is a replica set. If you have a standalone server,
- * use the Mongo(ServerAddress) constructor.
+ * use the Mongo(ServerAddress) constructor.
+ *
+ * If this is a list of mongos servers, it will pick the closest (lowest ping time) one to send all requests to,
+ * and automatically fail over to the next server if the closest is down.
+ *
* @see com.massivecraft.mcore.xlib.mongodb.ServerAddress
- * @param replicaSetSeeds Put as many servers as you can in the list and
- * the system will figure out the rest.
+ * @param seeds Put as many servers as you can in the list and the system will figure out the rest. This can
+ * either be a list of mongod servers in the same replica set or a list of mongos servers in the same
+ * sharded cluster.
* @throws MongoException
+ *
+ * @deprecated Replaced by {@link MongoClient#MongoClient(java.util.List)}
+ *
*/
- public Mongo( List replicaSetSeeds )
- throws MongoException {
- this( replicaSetSeeds , new MongoOptions() );
+ @Deprecated
+ public Mongo( List seeds ) {
+ this( seeds , new MongoOptions() );
}
/**
- * Creates a Mongo based on a replica set, or pair.
- * It will find all members (the master will be used by default).
+ * Creates a Mongo based on a list of replica set members or a list of mongos.
+ * It will find all members (the master will be used by default). If you pass in a single server in the list,
+ * the driver will still function as if it is a replica set. If you have a standalone server,
+ * use the Mongo(ServerAddress) constructor.
+ *
+ * If this is a list of mongos servers, it will pick the closest (lowest ping time) one to send all requests to,
+ * and automatically fail over to the next server if the closest is down.
+ *
* @see com.massivecraft.mcore.xlib.mongodb.ServerAddress
- * @param replicaSetSeeds put as many servers as you can in the list.
- * the system will figure the rest out
- * @param options default query options
+ * @param seeds Put as many servers as you can in the list and the system will figure out the rest. This can
+ * either be a list of mongod servers in the same replica set or a list of mongos servers in the same
+ * sharded cluster.
+ * @param options for configuring this Mongo instance
* @throws MongoException
+ *
+ * @deprecated Replaced by {@link MongoClient#MongoClient(java.util.List, MongoClientOptions)}
+ *
*/
- public Mongo( List replicaSetSeeds , MongoOptions options )
- throws MongoException {
-
- _addr = null;
- _addrs = replicaSetSeeds;
- _options = options;
- _applyMongoOptions();
- _connector = new DBTCPConnector( this , _addrs );
- _connector.start();
-
- _cleaner = new DBCleanerThread();
- _cleaner.start();
+ @Deprecated
+ public Mongo( List seeds , MongoOptions options ) {
+ this(MongoAuthority.dynamicSet(seeds), options);
}
/**
* Creates a Mongo described by a URI.
* If only one address is used it will only connect to that node, otherwise it will discover all nodes.
+ * If the URI contains database credentials, the database will be authenticated lazily on first use
+ * with those credentials.
* @param uri
* @see MongoURI
* examples:
- *
mongodb://127.0.0.1
- * mongodb://fred:foobar@127.0.0.1/
+ * mongodb://localhost
+ * mongodb://fred:foobar@localhost/
*
- * @throws MongoException
+ * @throws MongoException
* @throws UnknownHostException
* @dochub connections
+ *
+ * @deprecated Replaced by {@link MongoClient#MongoClient(MongoClientURI)}
+ *
*/
+ @Deprecated
+ public Mongo( MongoURI uri ) throws UnknownHostException {
+ this(getMongoAuthorityFromURI(uri), uri.getOptions());
+ }
- public Mongo( MongoURI uri )
- throws MongoException , UnknownHostException {
-
- _options = uri.getOptions();
+ /**
+ * Creates a Mongo based on an authority and options.
+ *
+ * Note: This constructor is provisional and is subject to change before the final release
+ *
+ * @param authority the authority
+ * @param options the options
+ */
+ Mongo(MongoAuthority authority, MongoOptions options) {
+ logger.info("Creating Mongo instance (driver version " + getVersion() + ") with authority " + authority + " and options " + options);
+ _authority = authority;
+ _options = options;
_applyMongoOptions();
- if ( uri.getHosts().size() == 1 ){
- _addr = new ServerAddress( uri.getHosts().get(0) );
- _addrs = null;
- _connector = new DBTCPConnector( this , _addr );
- }
- else {
- List replicaSetSeeds = new ArrayList( uri.getHosts().size() );
- for ( String host : uri.getHosts() )
- replicaSetSeeds.add( new ServerAddress( host ) );
- _addr = null;
- _addrs = replicaSetSeeds;
- _connector = new DBTCPConnector( this , replicaSetSeeds );
- }
+ _connector = new DBTCPConnector( this );
_connector.start();
- _cleaner = new DBCleanerThread();
- _cleaner.start();
+ if (_options.cursorFinalizerEnabled) {
+ _cleaner = new CursorCleanerThread();
+ _cleaner.start();
+ } else {
+ _cleaner = null;
+ }
}
/**
@@ -345,15 +376,13 @@ public class Mongo {
* @return
* @throws MongoException
*/
- @SuppressWarnings("rawtypes")
- public List getDatabaseNames()
- throws MongoException {
+ public List getDatabaseNames(){
BasicDBObject cmd = new BasicDBObject();
cmd.put("listDatabases", 1);
- CommandResult res = getDB( "admin" ).command(cmd, getOptions());
+ CommandResult res = getDB(ADMIN_DATABASE_NAME).command(cmd, getOptions());
res.throwOnError();
List l = (List)res.get("databases");
@@ -372,8 +401,7 @@ public class Mongo {
* @param dbName name of database to drop
* @throws MongoException
*/
- public void dropDatabase(String dbName)
- throws MongoException {
+ public void dropDatabase(String dbName){
getDB( dbName ).dropDatabase();
}
@@ -442,6 +470,7 @@ public class Mongo {
* Gets the list of server addresses currently seen by the connector.
* This includes addresses auto-discovered from a replica set.
* @return
+ * @throws MongoException
*/
public List getServerAddressList() {
return _connector.getServerAddressList();
@@ -457,12 +486,14 @@ public class Mongo {
_connector.close();
} catch (final Throwable t) { /* nada */ }
- _cleaner.interrupt();
+ if (_cleaner != null) {
+ _cleaner.interrupt();
- try {
- _cleaner.join();
- } catch (InterruptedException e) {
- //end early
+ try {
+ _cleaner.join();
+ } catch (InterruptedException e) {
+ //end early
+ }
}
}
@@ -505,10 +536,10 @@ public class Mongo {
}
/**
- * makes it possible to run read queries on slave nodes
+ * makes it possible to run read queries on secondary nodes
*
- * @deprecated Replaced with ReadPreference.SECONDARY
- * @see com.massivecraft.mcore.xlib.mongodb.ReadPreference.SECONDARY
+ * @deprecated Replaced with {@code ReadPreference.secondaryPreferred()}
+ * @see ReadPreference#secondaryPreferred()
*/
@Deprecated
public void slaveOk(){
@@ -552,8 +583,13 @@ public class Mongo {
*/
@SuppressWarnings("deprecation")
void _applyMongoOptions() {
- if (_options.slaveOk) slaveOk();
- setWriteConcern( _options.getWriteConcern() );
+ if (_options.slaveOk) {
+ slaveOk();
+ }
+ if (_options.getReadPreference() != null) {
+ setReadPreference(_options.getReadPreference());
+ }
+ setWriteConcern(_options.getWriteConcern());
}
/**
@@ -568,23 +604,42 @@ public class Mongo {
* Note that this value may change over time depending on which server is master.
* If the size is not known yet, a request may be sent to the master server
* @return the maximum size
+ * @throws MongoException
*/
public int getMaxBsonObjectSize() {
int maxsize = _connector.getMaxBsonObjectSize();
- if (maxsize == 0)
- maxsize = _connector.fetchMaxBsonObjectSize();
+ if (maxsize == 0) {
+ _connector.initDirectConnection();
+ }
+ maxsize = _connector.getMaxBsonObjectSize();
return maxsize > 0 ? maxsize : Bytes.MAX_OBJECT_SIZE;
}
- final ServerAddress _addr;
- final List _addrs;
+ boolean isMongosConnection() {
+ return _connector.isMongosConnection();
+ }
+
+ private static MongoAuthority getMongoAuthorityFromURI(final MongoURI uri) throws UnknownHostException {
+ if ( uri.getHosts().size() == 1 ){
+ return MongoAuthority.direct(new ServerAddress(uri.getHosts().get(0)), uri.getCredentials());
+ }
+ else {
+ List replicaSetSeeds = new ArrayList(uri.getHosts().size());
+ for ( String host : uri.getHosts() )
+ replicaSetSeeds.add( new ServerAddress( host ) );
+ return MongoAuthority.dynamicSet(replicaSetSeeds, uri.getCredentials());
+ }
+ }
+
final MongoOptions _options;
final DBTCPConnector _connector;
final ConcurrentMap _dbs = new ConcurrentHashMap();
private WriteConcern _concern = WriteConcern.NORMAL;
- private ReadPreference _readPref = ReadPreference.PRIMARY;
+ private ReadPreference _readPref = ReadPreference.primary();
final Bytes.OptionHolder _netOptions = new Bytes.OptionHolder( null );
- final DBCleanerThread _cleaner;
+ final CursorCleanerThread _cleaner;
+ final MongoAuthority _authority;
+
com.massivecraft.mcore.xlib.bson.util.SimplePool _bufferPool =
new com.massivecraft.mcore.xlib.bson.util.SimplePool( 1000 ){
@@ -599,44 +654,48 @@ public class Mongo {
* Forces the master server to fsync the RAM data to disk
* This is done automatically by the server at intervals, but can be forced for better reliability.
* @param async if true, the fsync will be done asynchronously on the server.
- * @return
+ * @return
+ * @throws MongoException
*/
public CommandResult fsync(boolean async) {
DBObject cmd = new BasicDBObject("fsync", 1);
if (async) {
cmd.put("async", 1);
}
- return getDB("admin").command(cmd);
+ return getDB(ADMIN_DATABASE_NAME).command(cmd);
}
/**
* Forces the master server to fsync the RAM data to disk, then lock all writes.
* The database will be read-only after this command returns.
- * @return
+ * @return
+ * @throws MongoException
*/
public CommandResult fsyncAndLock() {
DBObject cmd = new BasicDBObject("fsync", 1);
cmd.put("lock", 1);
- return getDB("admin").command(cmd);
+ return getDB(ADMIN_DATABASE_NAME).command(cmd);
}
/**
* Unlocks the database, allowing the write operations to go through.
* This command may be asynchronous on the server, which means there may be a small delay before the database becomes writable.
- * @return
+ * @return
+ * @throws MongoException
*/
public DBObject unlock() {
- DB db = getDB("admin");
+ DB db = getDB(ADMIN_DATABASE_NAME);
DBCollection col = db.getCollection("$cmd.sys.unlock");
return col.findOne();
}
/**
* Returns true if the database is locked (read-only), false otherwise.
- * @return
+ * @return
+ * @throws MongoException
*/
public boolean isLocked() {
- DB db = getDB("admin");
+ DB db = getDB(ADMIN_DATABASE_NAME);
DBCollection col = db.getCollection("$cmd.sys.inprog");
BasicDBObject res = (BasicDBObject) col.findOne();
if (res.containsField("fsyncLock")) {
@@ -663,7 +722,7 @@ public class Mongo {
* @throws UnknownHostException
*/
public Mongo connect( MongoURI uri )
- throws MongoException , UnknownHostException {
+ throws UnknownHostException {
String key = _toKey( uri );
@@ -693,7 +752,7 @@ public class Mongo {
buf.append( uri.getUsername() );
return buf.toString();
}
-
+
public static Holder singleton() { return _default; }
private static Holder _default = new Holder();
@@ -701,9 +760,9 @@ public class Mongo {
}
- class DBCleanerThread extends Thread {
+ class CursorCleanerThread extends Thread {
- DBCleanerThread() {
+ CursorCleanerThread() {
setDaemon(true);
setName("MongoCleaner" + hashCode());
}
@@ -728,15 +787,18 @@ public class Mongo {
@Override
public String toString() {
- StringBuilder str = new StringBuilder("Mongo: ");
- List list = getServerAddressList();
- if (list == null || list.size() == 0)
- str.append("null");
- else {
- for ( ServerAddress addr : list )
- str.append( addr.toString() ).append( ',' );
- str.deleteCharAt( str.length() - 1 );
- }
- return str.toString();
+ return "Mongo{" +
+ "authority=" + _authority +
+ ", options=" + _options +
+ '}';
+ }
+
+ /**
+ * Gets the authority, which includes the connection type, the server address(es), and the credentials.
+
+ * @return the authority
+ */
+ MongoAuthority getAuthority() {
+ return _authority;
}
}
diff --git a/src/com/massivecraft/mcore/xlib/mongodb/MongoAuthority.java b/src/com/massivecraft/mcore/xlib/mongodb/MongoAuthority.java
new file mode 100644
index 00000000..fb5030ab
--- /dev/null
+++ b/src/com/massivecraft/mcore/xlib/mongodb/MongoAuthority.java
@@ -0,0 +1,214 @@
+/**
+ * Copyright (c) 2008 - 2012 10gen, Inc.
+ *
+ * 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 com.massivecraft.mcore.xlib.mongodb;
+
+import com.massivecraft.mcore.xlib.bson.util.annotations.Immutable;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * This class represents the authority to which this client is connecting. It includes
+ * both the server address(es) and optional authentication credentials. The class name is informed by the
+ * URI RFC, which refers to the username/host/port
+ * part of a URI as the "authority".
+ *
+ * @since 2.11.0
+ */
+@Immutable
+class MongoAuthority {
+ private final Type type;
+ private final List serverAddresses;
+ private final MongoCredentialsStore credentialsStore;
+
+ /**
+ * Enumeration of the connection types.
+ */
+ enum Type {
+ Direct,
+ Set
+ }
+
+ /**
+ *
+ * @param serverAddress
+ * @return
+ */
+ public static MongoAuthority direct(ServerAddress serverAddress) {
+ return direct(serverAddress, (MongoCredential) null);
+ }
+
+ /**
+ *
+ * @param serverAddress
+ * @param credentials
+ * @return
+ */
+ public static MongoAuthority direct(ServerAddress serverAddress, MongoCredential credentials) {
+ return direct(serverAddress, new MongoCredentialsStore(credentials));
+ }
+
+ /**
+ *
+ * @param serverAddress
+ * @param credentialsStore
+ * @return
+ */
+ public static MongoAuthority direct(ServerAddress serverAddress, MongoCredentialsStore credentialsStore) {
+ return new MongoAuthority(serverAddress, credentialsStore);
+ }
+
+ /**
+ *
+ * @param serverAddresses
+ * @return
+ */
+ public static MongoAuthority dynamicSet(List serverAddresses) {
+ return dynamicSet(serverAddresses, (MongoCredential) null);
+ }
+
+ /**
+ *
+ * @param serverAddresses
+ * @param credentials
+ * @return
+ */
+ public static MongoAuthority dynamicSet(List serverAddresses, MongoCredential credentials) {
+ return dynamicSet(serverAddresses, new MongoCredentialsStore(credentials));
+ }
+
+ /**
+ *
+ * @param serverAddresses
+ * @param credentialsStore
+ * @return
+ */
+ public static MongoAuthority dynamicSet(List serverAddresses, MongoCredentialsStore credentialsStore) {
+ return new MongoAuthority(serverAddresses, Type.Set, credentialsStore);
+ }
+
+ /**
+ * Constructs an instance with a single server address and a store of authentication credentials.
+ * This will be a direct connection, even if it's part of a replica set.
+ *
+ * @param serverAddress the server address of a mongo server
+ */
+ private MongoAuthority(final ServerAddress serverAddress, MongoCredentialsStore credentialsStore) {
+ if (serverAddress == null) {
+ throw new IllegalArgumentException("serverAddress can not be null");
+ }
+
+ if (credentialsStore == null) {
+ throw new IllegalArgumentException("credentialsStore can not be null");
+ }
+
+ this.serverAddresses = Arrays.asList(serverAddress);
+ this.credentialsStore = credentialsStore;
+ this.type = Type.Direct;
+ }
+
+ /**
+ * Constructs an instance with a list of server addresses, which may either be a list of mongos servers
+ * or a list of members of a replica set, and a store of authentication credentials.
+ *
+ * @param serverAddresses the server addresses
+ * @param credentialsStore the credentials store
+ */
+ private MongoAuthority(final List serverAddresses, Type type, MongoCredentialsStore credentialsStore) {
+ if (serverAddresses == null) {
+ throw new IllegalArgumentException("serverAddresses can not be null");
+ }
+
+ if (credentialsStore == null) {
+ throw new IllegalArgumentException("credentialsStore can not be null");
+ }
+
+ if (type == null) {
+ throw new IllegalArgumentException("type can not be null");
+ }
+
+ if (type == Type.Direct) {
+ throw new IllegalArgumentException("type can not be Direct with a list of server addresses");
+ }
+
+ this.type = type;
+ this.serverAddresses = new ArrayList(serverAddresses);
+ this.credentialsStore = credentialsStore;
+ }
+
+ /**
+ * Returns the list of server addresses.
+ *
+ * @return the server address list
+ */
+ public List getServerAddresses() {
+ return serverAddresses == null ? null : Collections.unmodifiableList(serverAddresses);
+ }
+
+ /**
+ * Gets the credentials store. If this instance was constructed with a single credential, this store will
+ * contain it.
+ *
+ * @return the credentials store
+ */
+ public MongoCredentialsStore getCredentialsStore() {
+ return credentialsStore;
+ }
+
+ /**
+ * Gets the authority type
+ *
+ * @return the authority type
+ */
+ public Type getType() {
+ return type;
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ final MongoAuthority that = (MongoAuthority) o;
+
+ if (!credentialsStore.equals(that.credentialsStore)) return false;
+ if (!serverAddresses.equals(that.serverAddresses)) return false;
+ if (type != that.type) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = credentialsStore.hashCode();
+ result = 31 * result + serverAddresses.hashCode();
+ result = 31 * result + type.hashCode();
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "MongoAuthority{" +
+ "type=" + type +
+ ", serverAddresses=" + serverAddresses +
+ ", credentials=" + credentialsStore +
+ '}';
+ }
+}
diff --git a/src/com/massivecraft/mcore/xlib/mongodb/MongoClient.java b/src/com/massivecraft/mcore/xlib/mongodb/MongoClient.java
new file mode 100644
index 00000000..0ed891e5
--- /dev/null
+++ b/src/com/massivecraft/mcore/xlib/mongodb/MongoClient.java
@@ -0,0 +1,286 @@
+/**
+ * Copyright (c) 2008 - 2012 10gen, Inc.
+ *
+ * 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 com.massivecraft.mcore.xlib.mongodb;
+
+import java.net.UnknownHostException;
+import java.util.List;
+
+/**
+ * A MongoDB client with internal connection pooling. For most applications, you should have one MongoClient instance
+ * for the entire JVM.
+ *
+ * The following are equivalent, and all connect to the local database running on the default port:
+ *
+ * MongoClient mongoClient1 = new MongoClient();
+ * MongoClient mongoClient1 = new MongoClient("localhost");
+ * MongoClient mongoClient2 = new MongoClient("localhost", 27017);
+ * MongoClient mongoClient4 = new MongoClient(new ServerAddress("localhost"));
+ * MongoClient mongoClient5 = new MongoClient(new ServerAddress("localhost"), new MongoClientOptions.Builder().build());
+ *
+ *
+ * You can connect to a
+ * replica set using the Java driver by passing
+ * a ServerAddress list to the MongoClient constructor. For example:
+ *
+ * MongoClient mongoClient = new MongoClient(Arrays.asList(
+ * new ServerAddress("localhost", 27017),
+ * new ServerAddress("localhost", 27018),
+ * new ServerAddress("localhost", 27019)));
+ *
+ * You can connect to a sharded cluster using the same constructor. MongoClient will auto-detect whether the servers are
+ * a list of replica set members or a list of mongos servers.
+ *
+ * By default, all read and write operations will be made on the primary, but it's possible to read from secondaries
+ * by changing the read preference:
+ *
+ * mongoClient.setReadPreference(ReadPreference.secondaryPreferred());
+ *
+ * By default, all write operations will wait for acknowledgment by the server, as the default write concern is
+ * {@code WriteConcern.ACKNOWLEDGED}.
+ *
+ * Note: This class supersedes the {@code Mongo} class. While it extends {@code Mongo}, it differs from it in that
+ * the default write concern is to wait for acknowledgment from the server of all write operations. In addition, its
+ * constructors accept instances of {@code MongoClientOptions} and {@code MongoClientURI}, which both also
+ * set the same default write concern.
+ *
+ * In general, users of this class will pick up all of the default options specified in {@code MongoClientOptions}. In
+ * particular, note that the default value of the connectionsPerHost option has been increased to 100 from the old
+ * default value of 10 used by the superseded {@code Mongo} class.
+ *
+ * @see ReadPreference#primary()
+ * @see com.massivecraft.mcore.xlib.mongodb.WriteConcern#ACKNOWLEDGED
+ * @see MongoClientOptions
+ * @see MongoClientURI
+ * @since 2.10.0
+ */
+public class MongoClient extends Mongo {
+
+ private final MongoClientOptions options;
+
+ /**
+ * Creates an instance based on a (single) mongodb node (localhost, default port).
+ *
+ * @throws UnknownHostException
+ * @throws MongoException
+ */
+ public MongoClient() throws UnknownHostException {
+ this(new ServerAddress());
+ }
+
+ /**
+ * Creates a Mongo instance based on a (single) mongodb node.
+ *
+ * @param host server to connect to in format host[:port]
+ * @throws UnknownHostException if the database host cannot be resolved
+ * @throws MongoException
+ */
+ public MongoClient(String host) throws UnknownHostException {
+ this(new ServerAddress(host));
+ }
+
+ /**
+ * Creates a Mongo instance based on a (single) mongodb node (default port).
+ *
+ * @param host server to connect to in format host[:port]
+ * @param options default query options
+ * @throws UnknownHostException if the database host cannot be resolved
+ * @throws MongoException
+ */
+ public MongoClient(String host, MongoClientOptions options) throws UnknownHostException {
+ this(new ServerAddress(host), options);
+ }
+
+ /**
+ * Creates a Mongo instance based on a (single) mongodb node.
+ *
+ * @param host the database's host address
+ * @param port the port on which the database is running
+ * @throws UnknownHostException if the database host cannot be resolved
+ * @throws MongoException
+ */
+ public MongoClient(String host, int port) throws UnknownHostException {
+ this(new ServerAddress(host, port));
+ }
+
+ /**
+ * Creates a Mongo instance based on a (single) mongodb node
+ *
+ * @param addr the database address
+ * @throws MongoException
+ * @see com.massivecraft.mcore.xlib.mongodb.ServerAddress
+ */
+ public MongoClient(ServerAddress addr) {
+ this(addr, new MongoClientOptions.Builder().build());
+ }
+
+ /**
+ * Creates a Mongo instance based on a (single) mongodb node and a list of credentials
+ *
+ * @param addr the database address
+ * @param credentialsList the list of credentials used to authenticate all connections
+ * @throws MongoException
+ * @see com.massivecraft.mcore.xlib.mongodb.ServerAddress
+ * @since 2.11.0
+ */
+ public MongoClient(ServerAddress addr, List credentialsList) {
+ this(addr, credentialsList, new MongoClientOptions.Builder().build());
+ }
+
+ /**
+ * Creates a Mongo instance based on a (single) mongo node using a given ServerAddress and default options.
+ *
+ * @param addr the database address
+ * @param options default options
+ * @throws MongoException
+ * @see com.massivecraft.mcore.xlib.mongodb.ServerAddress
+ */
+ public MongoClient(ServerAddress addr, MongoClientOptions options) {
+ this(addr, null, options);
+ }
+
+ /**
+ * Creates a Mongo instance based on a (single) mongo node using a given ServerAddress and default options.
+ *
+ * @param addr the database address
+ * @param credentialsList the list of credentials used to authenticate all connections
+ * @param options default options
+ * @throws MongoException
+ * @see com.massivecraft.mcore.xlib.mongodb.ServerAddress
+ * @since 2.11.0
+ */
+ @SuppressWarnings("deprecation")
+ public MongoClient(ServerAddress addr, List credentialsList, MongoClientOptions options) {
+ super(MongoAuthority.direct(addr, new MongoCredentialsStore(credentialsList)), new MongoOptions(options));
+ this.options = options;
+ }
+
+ /**
+ * Creates a Mongo based on a list of replica set members or a list of mongos.
+ * It will find all members (the master will be used by default). If you pass in a single server in the list,
+ * the driver will still function as if it is a replica set. If you have a standalone server,
+ * use the Mongo(ServerAddress) constructor.
+ *
+ * If this is a list of mongos servers, it will pick the closest (lowest ping time) one to send all requests to,
+ * and automatically fail over to the next server if the closest is down.
+ *
+ * @param seeds Put as many servers as you can in the list and the system will figure out the rest. This can
+ * either be a list of mongod servers in the same replica set or a list of mongos servers in the same
+ * sharded cluster.
+ * @throws MongoException
+ * @see com.massivecraft.mcore.xlib.mongodb.ServerAddress
+ */
+ public MongoClient(List seeds) {
+ this(seeds, null, new MongoClientOptions.Builder().build());
+ }
+
+ /**
+ * Creates a Mongo based on a list of replica set members or a list of mongos.
+ * It will find all members (the master will be used by default). If you pass in a single server in the list,
+ * the driver will still function as if it is a replica set. If you have a standalone server,
+ * use the Mongo(ServerAddress) constructor.
+ *
+ * If this is a list of mongos servers, it will pick the closest (lowest ping time) one to send all requests to,
+ * and automatically fail over to the next server if the closest is down.
+ *
+ * @param seeds Put as many servers as you can in the list and the system will figure out the rest. This can
+ * either be a list of mongod servers in the same replica set or a list of mongos servers in the same
+ * sharded cluster. \
+ * @param credentialsList the list of credentials used to authenticate all connections
+ * @throws MongoException
+ * @see com.massivecraft.mcore.xlib.mongodb.ServerAddress
+ * @since 2.11.0
+ */
+ public MongoClient(List seeds, List credentialsList) {
+ this(seeds, credentialsList, new MongoClientOptions.Builder().build());
+ }
+
+
+ /**
+ * Creates a Mongo based on a list of replica set members or a list of mongos.
+ * It will find all members (the master will be used by default). If you pass in a single server in the list,
+ * the driver will still function as if it is a replica set. If you have a standalone server,
+ * use the Mongo(ServerAddress) constructor.
+ *
+ * If this is a list of mongos servers, it will pick the closest (lowest ping time) one to send all requests to,
+ * and automatically fail over to the next server if the closest is down.
+ *
+ * @param seeds Put as many servers as you can in the list and the system will figure out the rest. This can
+ * either be a list of mongod servers in the same replica set or a list of mongos servers in the same
+ * sharded cluster.
+ * @param options default options
+ * @throws MongoException
+ * @see com.massivecraft.mcore.xlib.mongodb.ServerAddress
+ */
+ public MongoClient(List seeds, MongoClientOptions options) {
+ this(seeds, null, options);
+ }
+
+ /**
+ * Creates a Mongo based on a list of replica set members or a list of mongos.
+ * It will find all members (the master will be used by default). If you pass in a single server in the list,
+ * the driver will still function as if it is a replica set. If you have a standalone server,
+ * use the Mongo(ServerAddress) constructor.
+ *
+ * If this is a list of mongos servers, it will pick the closest (lowest ping time) one to send all requests to,
+ * and automatically fail over to the next server if the closest is down.
+ *
+ * @param seeds Put as many servers as you can in the list and the system will figure out the rest. This can
+ * either be a list of mongod servers in the same replica set or a list of mongos servers in the same
+ * sharded cluster.
+ * @param credentialsList the list of credentials used to authenticate all connections
+ * @param options default options
+ * @throws MongoException
+ * @see com.massivecraft.mcore.xlib.mongodb.ServerAddress
+ * @since 2.11.0
+ */
+ @SuppressWarnings("deprecation")
+ public MongoClient(List seeds, List credentialsList, MongoClientOptions options) {
+ super(MongoAuthority.dynamicSet(seeds, new MongoCredentialsStore(credentialsList)), new MongoOptions(options));
+ this.options = options;
+ }
+
+
+ /**
+ * Creates a Mongo described by a URI.
+ * If only one address is used it will only connect to that node, otherwise it will discover all nodes.
+ * @param uri the URI
+ * @throws MongoException
+ * @throws UnknownHostException
+ * @see MongoURI
+ * @dochub connections
+ */
+ @SuppressWarnings("deprecation")
+ public MongoClient(MongoClientURI uri) throws UnknownHostException {
+ super(new MongoURI(uri));
+ this.options = uri.getOptions();
+ }
+
+ /**
+ * Gets the list of credentials that this client authenticates all connections with
+ *
+ * @return the list of credentials
+ * @since 2.11.0
+ */
+ public List getCredentialsList() {
+ return getAuthority().getCredentialsStore().asList();
+ }
+
+ public MongoClientOptions getMongoClientOptions() {
+ return options;
+ }
+}
\ No newline at end of file
diff --git a/src/com/massivecraft/mcore/xlib/mongodb/MongoClientOptions.java b/src/com/massivecraft/mcore/xlib/mongodb/MongoClientOptions.java
new file mode 100644
index 00000000..271441c4
--- /dev/null
+++ b/src/com/massivecraft/mcore/xlib/mongodb/MongoClientOptions.java
@@ -0,0 +1,600 @@
+/**
+ * Copyright (c) 2008 - 2012 10gen, Inc.
+ *
+ * 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 com.massivecraft.mcore.xlib.mongodb;
+
+import com.massivecraft.mcore.xlib.bson.util.annotations.Immutable;
+
+import javax.net.SocketFactory;
+
+/**
+ * Various settings to control the behavior of a MongoClient
.
+ *
+ * Note: This class is a replacement for {@code MongoOptions}, to be used with {@code MongoClient}. The main difference
+ * in behavior is that the default write concern is {@code WriteConcern.ACKNOWLEDGED}.
+ *
+ * @see MongoClient
+ * @since 2.10.0
+ */
+@Immutable
+public class MongoClientOptions {
+ /**
+ * A builder for MongoClientOptions so that MongoClientOptions can be immutable, and to support easier
+ * construction through chaining.
+ *
+ * @since 2.10.0
+ */
+ public static class Builder {
+
+ private String description;
+ private int connectionsPerHost = 100;
+ private int threadsAllowedToBlockForConnectionMultiplier = 5;
+ private int maxWaitTime = 1000 * 60 * 2;
+ private int connectTimeout = 1000 * 10;
+ private int socketTimeout = 0;
+ private boolean socketKeepAlive = false;
+ private boolean autoConnectRetry = false;
+ private long maxAutoConnectRetryTime = 0;
+ private ReadPreference readPreference = ReadPreference.primary();
+ private DBDecoderFactory dbDecoderFactory = DefaultDBDecoder.FACTORY;
+ private DBEncoderFactory dbEncoderFactory = DefaultDBEncoder.FACTORY;
+ private WriteConcern writeConcern = WriteConcern.ACKNOWLEDGED;
+ private SocketFactory socketFactory = SocketFactory.getDefault();
+ private boolean cursorFinalizerEnabled = true;
+ private boolean alwaysUseMBeans = false;
+
+ /**
+ * Sets the description.
+ *
+ * @param description the description of this MongoClient
+ * @return {@code this}
+ * @see com.massivecraft.mcore.xlib.mongodb.MongoClientOptions#getDescription()
+ */
+ public Builder description(final String description) {
+ this.description = description;
+ return this;
+ }
+
+ /**
+ * Sets the maximum number of connections per host.
+ *
+ * @param connectionsPerHost maximum number of connections
+ * @return {@code this}
+ * @throws IllegalArgumentException if connnectionsPerHost < 1
+ * @see com.massivecraft.mcore.xlib.mongodb.MongoClientOptions#getConnectionsPerHost()
+ */
+ public Builder connectionsPerHost(final int connectionsPerHost) {
+ if (connectionsPerHost < 1) {
+ throw new IllegalArgumentException("Minimum value is 1");
+ }
+ this.connectionsPerHost = connectionsPerHost;
+ return this;
+ }
+
+ /**
+ * Sets the multiplier for number of threads allowed to block waiting for a connection.
+ *
+ * @param threadsAllowedToBlockForConnectionMultiplier
+ * the multiplier
+ * @return {@code this}
+ * @throws IllegalArgumentException if threadsAllowedToBlockForConnectionMultiplier < 1
+ * @see com.massivecraft.mcore.xlib.mongodb.MongoClientOptions#getThreadsAllowedToBlockForConnectionMultiplier()
+ */
+ public Builder threadsAllowedToBlockForConnectionMultiplier(final int threadsAllowedToBlockForConnectionMultiplier) {
+ if (threadsAllowedToBlockForConnectionMultiplier < 1) {
+ throw new IllegalArgumentException("Minimum value is 1");
+ }
+ this.threadsAllowedToBlockForConnectionMultiplier = threadsAllowedToBlockForConnectionMultiplier;
+ return this;
+ }
+
+ /**
+ * Sets the maximum time that a thread will block waiting for a connection.
+ *
+ * @param maxWaitTime the maximum wait time
+ * @return {@code this}
+ * @throws IllegalArgumentException if maxWaitTime < 0
+ * @see com.massivecraft.mcore.xlib.mongodb.MongoClientOptions#getMaxWaitTime()
+ */
+ public Builder maxWaitTime(final int maxWaitTime) {
+ if (maxWaitTime < 0) {
+ throw new IllegalArgumentException("Minimum value is 0");
+ }
+ this.maxWaitTime = maxWaitTime;
+ return this;
+ }
+
+ /**
+ * Sets the connection timeout.
+ *
+ * @param connectTimeout the connection timeout
+ * @return {@code this}
+ * @see com.massivecraft.mcore.xlib.mongodb.MongoClientOptions#getConnectTimeout()
+ */
+ public Builder connectTimeout(final int connectTimeout) {
+ if (connectTimeout < 0) {
+ throw new IllegalArgumentException("Minimum value is 0");
+ }
+ this.connectTimeout = connectTimeout;
+ return this;
+ }
+
+ /**
+ * Sets the socket timeout.
+ *
+ * @param socketTimeout the socket timeout
+ * @return {@code this}
+ * @see com.massivecraft.mcore.xlib.mongodb.MongoClientOptions#getSocketTimeout()
+ */
+ public Builder socketTimeout(final int socketTimeout) {
+ if (socketTimeout < 0) {
+ throw new IllegalArgumentException("Minimum value is 0");
+ }
+ this.socketTimeout = socketTimeout;
+ return this;
+ }
+
+ /**
+ * Sets whether socket keep alive is enabled.
+ *
+ * @param socketKeepAlive keep alive
+ * @return {@code this}
+ * @see com.massivecraft.mcore.xlib.mongodb.MongoClientOptions#isSocketKeepAlive()
+ */
+ public Builder socketKeepAlive(final boolean socketKeepAlive) {
+ this.socketKeepAlive = socketKeepAlive;
+ return this;
+ }
+
+ /**
+ * Sets whether auto connect retry is enabled.
+ *
+ * @param autoConnectRetry auto connect retry
+ * @return {@code this}
+ * @see MongoClientOptions#isAutoConnectRetry()
+ */
+ public Builder autoConnectRetry(final boolean autoConnectRetry) {
+ this.autoConnectRetry = autoConnectRetry;
+ return this;
+ }
+
+ /**
+ * Sets the maximum auto connect retry time.
+ *
+ * @param maxAutoConnectRetryTime the maximum auto connect retry time
+ * @return {@code this}
+ * @see MongoClientOptions#getMaxAutoConnectRetryTime()
+ */
+ public Builder maxAutoConnectRetryTime(final long maxAutoConnectRetryTime) {
+ if (maxAutoConnectRetryTime < 0) {
+ throw new IllegalArgumentException("Minimum value is 0");
+ }
+ this.maxAutoConnectRetryTime = maxAutoConnectRetryTime;
+ return this;
+ }
+
+ /**
+ * Sets the read preference.
+ *
+ * @param readPreference read preference
+ * @return {@code this}
+ * @see MongoClientOptions#getReadPreference()
+ */
+ public Builder readPreference(final ReadPreference readPreference) {
+ if (readPreference == null) {
+ throw new IllegalArgumentException("null is not a legal value");
+ }
+ this.readPreference = readPreference;
+ return this;
+ }
+
+ /**
+ * Sets the decoder factory.
+ *
+ * @param dbDecoderFactory the decoder factory
+ * @return {@code this}
+ * @see MongoClientOptions#getDbDecoderFactory()
+ */
+ public Builder dbDecoderFactory(final DBDecoderFactory dbDecoderFactory) {
+ if (dbDecoderFactory == null) {
+ throw new IllegalArgumentException("null is not a legal value");
+ }
+ this.dbDecoderFactory = dbDecoderFactory;
+ return this;
+ }
+
+ /**
+ * Sets the encoder factory.
+ *
+ * @param dbEncoderFactory the encoder factory
+ * @return {@code this}
+ * @see MongoClientOptions#getDbEncoderFactory()
+ */
+ public Builder dbEncoderFactory(final DBEncoderFactory dbEncoderFactory) {
+ if (dbEncoderFactory == null) {
+ throw new IllegalArgumentException("null is not a legal value");
+ }
+ this.dbEncoderFactory = dbEncoderFactory;
+ return this;
+ }
+
+ /**
+ * Sets the write concern.
+ *
+ * @param writeConcern the write concern
+ * @return {@code this}
+ * @see MongoClientOptions#getWriteConcern()
+ */
+ public Builder writeConcern(final WriteConcern writeConcern) {
+ if (writeConcern == null) {
+ throw new IllegalArgumentException("null is not a legal value");
+ }
+ this.writeConcern = writeConcern;
+ return this;
+ }
+
+ /**
+ * Sets the socket factory.
+ *
+ * @param socketFactory the socket factory
+ * @return {@code this}
+ * @see MongoClientOptions#getSocketFactory()
+ */
+ public Builder socketFactory(final SocketFactory socketFactory) {
+ if (socketFactory == null) {
+ throw new IllegalArgumentException("null is not a legal value");
+ }
+ this.socketFactory = socketFactory;
+ return this;
+ }
+
+ /**
+ * Sets whether cursor finalizers are enabled.
+ *
+ * @param cursorFinalizerEnabled whether cursor finalizers are enabled.
+ * @return {@code this}
+ * @see MongoClientOptions#isCursorFinalizerEnabled()
+ */
+ public Builder cursorFinalizerEnabled(final boolean cursorFinalizerEnabled) {
+ this.cursorFinalizerEnabled = cursorFinalizerEnabled;
+ return this;
+ }
+
+ /**
+ * Sets whether JMX beans registered by the driver should always be MBeans, regardless of whether the VM is
+ * Java 6 or greater. If false, the driver will use MXBeans if the VM is Java 6 or greater, and use MBeans if
+ * the VM is Java 5.
+ *
+ * @param alwaysUseMBeans true if driver should always use MBeans, regardless of VM version
+ * @return this
+ * @see MongoClientOptions#isAlwaysUseMBeans()
+ */
+ public Builder alwaysUseMBeans(final boolean alwaysUseMBeans) {
+ this.alwaysUseMBeans = alwaysUseMBeans;
+ return this;
+ }
+
+ /**
+ * Sets defaults to be what they are in {@code MongoOptions}.
+ *
+ * @return {@code this}
+ * @see MongoOptions
+ */
+ public Builder legacyDefaults() {
+ connectionsPerHost = 10;
+ writeConcern = WriteConcern.NORMAL;
+ return this;
+ }
+
+ /**
+ * Build an instance of MongoClientOptions.
+ *
+ * @return the options from this builder
+ */
+ public MongoClientOptions build() {
+ return new MongoClientOptions(this);
+ }
+ }
+
+ /**
+ * Create a new Builder instance. This is a convenience method, equivalent to {@code new MongoClientOptions.Builder()}.
+ *
+ * @return a new instance of a Builder
+ */
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ /**
+ * Gets the description for this MongoClient, which is used in various places like logging and JMX.
+ *
+ * Default is null.
+ *
+ * @return the description
+ */
+ public String getDescription() {
+ return description;
+ }
+
+ /**
+ * The maximum number of connections allowed per host for this MongoClient instance.
+ * Those connections will be kept in a pool when idle.
+ * Once the pool is exhausted, any operation requiring a connection will block waiting for an available connection.
+ *
+ * Default is 100.
+ *
+ * @return the maximum size of the connection pool per host
+ * @see MongoClientOptions#getThreadsAllowedToBlockForConnectionMultiplier()
+ */
+ public int getConnectionsPerHost() {
+ return connectionsPerHost;
+ }
+
+ /**
+ * this multiplier, multiplied with the connectionsPerHost setting, gives the maximum number of threads that
+ * may be waiting for a connection to become available from the pool. All further threads will get an exception right
+ * away. For example if connectionsPerHost is 10 and threadsAllowedToBlockForConnectionMultiplier is 5, then up to 50
+ * threads can wait for a connection.
+ *
+ * Default is 5.
+ *
+ * @return the multiplier
+ */
+ public int getThreadsAllowedToBlockForConnectionMultiplier() {
+ return threadsAllowedToBlockForConnectionMultiplier;
+ }
+
+ /**
+ * The maximum wait time in milliseconds that a thread may wait for a connection to become available.
+ *
+ * Default is 120,000. A value of 0 means that it will not wait. A negative value means to wait indefinitely.
+ *
+ * @return the maximum wait time.
+ */
+ public int getMaxWaitTime() {
+ return maxWaitTime;
+ }
+
+ /**
+ * The connection timeout in milliseconds. A value of 0 means no timeout.
+ * It is used solely when establishing a new connection {@link java.net.Socket#connect(java.net.SocketAddress, int) }
+ *
+ * Default is 10,000.
+ *
+ * @return the socket connect timeout
+ */
+ public int getConnectTimeout() {
+ return connectTimeout;
+ }
+
+ /**
+ * The socket timeout in milliseconds.
+ * It is used for I/O socket read and write operations {@link java.net.Socket#setSoTimeout(int)}
+ *
+ * Default is 0 and means no timeout.
+ *
+ * @return the socket timeout
+ */
+ public int getSocketTimeout() {
+ return socketTimeout;
+ }
+
+ /**
+ * This flag controls the socket keep alive feature that keeps a connection alive through firewalls {@link java.net.Socket#setKeepAlive(boolean)}
+ *
+ * * Default is false.
+ *
+ * @return whether keep-alive is enabled on each socket
+ */
+ public boolean isSocketKeepAlive() {
+ return socketKeepAlive;
+ }
+
+ /**
+ * If true, the driver will keep trying to connect to the same server in case that the socket cannot be established.
+ * There is maximum amount of time to keep retrying, which is 15s by default.
+ * This can be useful to avoid some exceptions being thrown when a server is down temporarily by blocking the operations.
+ * It also can be useful to smooth the transition to a new master (so that a new master is elected within the retry time).
+ * Note that when using this flag:
+ * - for a replica set, the driver will trying to connect to the old master for that time, instead of failing over to the new one right away
+ * - this does not prevent exception from being thrown in read/write operations on the socket, which must be handled by application
+ *
+ * Even if this flag is false, the driver already has mechanisms to automatically recreate broken connections and retry the read operations.
+ * Default is false.
+ *
+ * @return whether socket connect is retried
+ */
+ public boolean isAutoConnectRetry() {
+ return autoConnectRetry;
+ }
+
+ /**
+ * The maximum amount of time in MS to spend retrying to open connection to the same server.
+ * Default is 0, which means to use the default 15s if autoConnectRetry is on.
+ *
+ * @return the maximum socket connect retry time.
+ */
+ public long getMaxAutoConnectRetryTime() {
+ return maxAutoConnectRetryTime;
+ }
+
+ /**
+ * The read preference to use for queries, map-reduce, aggregation, and count.
+ *
+ * Default is {@code ReadPreference.primary()}.
+ *
+ * @return the read preference
+ * @see com.massivecraft.mcore.xlib.mongodb.ReadPreference#primary()
+ */
+ public ReadPreference getReadPreference() {
+ return readPreference;
+ }
+
+ /**
+ * Override the decoder factory. Default is for the standard Mongo Java driver configuration.
+ *
+ * @return the decoder factory
+ */
+ public DBDecoderFactory getDbDecoderFactory() {
+ return dbDecoderFactory;
+ }
+
+ /**
+ * Override the encoder factory. Default is for the standard Mongo Java driver configuration.
+ *
+ * @return the encoder factory
+ */
+ public DBEncoderFactory getDbEncoderFactory() {
+ return dbEncoderFactory;
+ }
+
+ /**
+ * The write concern to use.
+ *
+ * Default is {@code WriteConcern.ACKNOWLEDGED}.
+ *
+ * @return the write concern
+ * @see WriteConcern#ACKNOWLEDGED
+ */
+ public WriteConcern getWriteConcern() {
+ return writeConcern;
+ }
+
+ /**
+ * The socket factory for creating sockets to the mongo server.
+ *
+ * Default is SocketFactory.getDefault()
+ *
+ * @return the socket factory
+ */
+ public SocketFactory getSocketFactory() {
+ return socketFactory;
+ }
+
+ /**
+ * Gets whether there is a a finalize method created that cleans up instances of DBCursor that the client
+ * does not close. If you are careful to always call the close method of DBCursor, then this can safely be set to false.
+ *
+ * Default is true.
+ *
+ * @return whether finalizers are enabled on cursors
+ * @see DBCursor
+ * @see com.massivecraft.mcore.xlib.mongodb.DBCursor#close()
+ */
+ public boolean isCursorFinalizerEnabled() {
+ return cursorFinalizerEnabled;
+ }
+
+ /**
+ * Gets whether JMX beans registered by the driver should always be MBeans, regardless of whether the VM is
+ * Java 6 or greater. If false, the driver will use MXBeans if the VM is Java 6 or greater, and use MBeans if
+ * the VM is Java 5.
+ *
+ * Default is false.
+ *
+ */
+ public boolean isAlwaysUseMBeans() {
+ return alwaysUseMBeans;
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ final MongoClientOptions that = (MongoClientOptions) o;
+
+ if (alwaysUseMBeans != that.alwaysUseMBeans) return false;
+ if (autoConnectRetry != that.autoConnectRetry) return false;
+ if (connectTimeout != that.connectTimeout) return false;
+ if (connectionsPerHost != that.connectionsPerHost) return false;
+ if (cursorFinalizerEnabled != that.cursorFinalizerEnabled) return false;
+ if (maxAutoConnectRetryTime != that.maxAutoConnectRetryTime) return false;
+ if (maxWaitTime != that.maxWaitTime) return false;
+ if (socketKeepAlive != that.socketKeepAlive) return false;
+ if (socketTimeout != that.socketTimeout) return false;
+ if (threadsAllowedToBlockForConnectionMultiplier != that.threadsAllowedToBlockForConnectionMultiplier)
+ return false;
+ if (!dbDecoderFactory.equals(that.dbDecoderFactory)) return false;
+ if (!dbEncoderFactory.equals(that.dbEncoderFactory)) return false;
+ if (description != null ? !description.equals(that.description) : that.description != null) return false;
+ if (!readPreference.equals(that.readPreference)) return false;
+ // Compare SocketFactory Class, since some equivalent SocketFactory instances are not equal to each other
+ if (!socketFactory.getClass().equals(that.socketFactory.getClass())) return false;
+ if (!writeConcern.equals(that.writeConcern)) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = description != null ? description.hashCode() : 0;
+ result = 31 * result + connectionsPerHost;
+ result = 31 * result + threadsAllowedToBlockForConnectionMultiplier;
+ result = 31 * result + maxWaitTime;
+ result = 31 * result + connectTimeout;
+ result = 31 * result + socketTimeout;
+ result = 31 * result + (socketKeepAlive ? 1 : 0);
+ result = 31 * result + (autoConnectRetry ? 1 : 0);
+ result = 31 * result + (int) (maxAutoConnectRetryTime ^ (maxAutoConnectRetryTime >>> 32));
+ result = 31 * result + readPreference.hashCode();
+ result = 31 * result + dbDecoderFactory.hashCode();
+ result = 31 * result + dbEncoderFactory.hashCode();
+ result = 31 * result + writeConcern.hashCode();
+ result = 31 * result + socketFactory.hashCode();
+ result = 31 * result + (cursorFinalizerEnabled ? 1 : 0);
+ result = 31 * result + (alwaysUseMBeans ? 1 : 0);
+ return result;
+ }
+
+ private MongoClientOptions(final Builder builder) {
+ description = builder.description;
+ connectionsPerHost = builder.connectionsPerHost;
+ threadsAllowedToBlockForConnectionMultiplier = builder.threadsAllowedToBlockForConnectionMultiplier;
+ maxWaitTime = builder.maxWaitTime;
+ connectTimeout = builder.connectTimeout;
+ socketTimeout = builder.socketTimeout;
+ autoConnectRetry = builder.autoConnectRetry;
+ socketKeepAlive = builder.socketKeepAlive;
+ maxAutoConnectRetryTime = builder.maxAutoConnectRetryTime;
+ readPreference = builder.readPreference;
+ dbDecoderFactory = builder.dbDecoderFactory;
+ dbEncoderFactory = builder.dbEncoderFactory;
+ writeConcern = builder.writeConcern;
+ socketFactory = builder.socketFactory;
+ cursorFinalizerEnabled = builder.cursorFinalizerEnabled;
+ alwaysUseMBeans = builder.alwaysUseMBeans;
+ }
+
+
+ private final String description;
+ private final int connectionsPerHost;
+ private final int threadsAllowedToBlockForConnectionMultiplier;
+ private final int maxWaitTime;
+ private final int connectTimeout;
+ private final int socketTimeout;
+ private final boolean socketKeepAlive;
+ private final boolean autoConnectRetry;
+ private final long maxAutoConnectRetryTime;
+ private final ReadPreference readPreference;
+ private final DBDecoderFactory dbDecoderFactory;
+ private final DBEncoderFactory dbEncoderFactory;
+ private final WriteConcern writeConcern;
+ private final SocketFactory socketFactory;
+ private final boolean cursorFinalizerEnabled;
+ private final boolean alwaysUseMBeans;
+}
diff --git a/src/com/massivecraft/mcore/xlib/mongodb/MongoClientURI.java b/src/com/massivecraft/mcore/xlib/mongodb/MongoClientURI.java
new file mode 100644
index 00000000..82f08124
--- /dev/null
+++ b/src/com/massivecraft/mcore/xlib/mongodb/MongoClientURI.java
@@ -0,0 +1,612 @@
+/**
+ * Copyright (c) 2008 - 2012 10gen, Inc.
+ *
+ * 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 com.massivecraft.mcore.xlib.mongodb;
+
+import javax.net.ssl.SSLSocketFactory;
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.logging.Logger;
+
+
+/**
+ * Represents a URI
+ * which can be used to create a MongoClient instance. The URI describes the hosts to
+ * be used and options.
+ * The format of the URI is:
+ *
+ * mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]
+ *
+ *
+ * - {@code mongodb://} is a required prefix to identify that this is a string in the standard connection format.
+ * - {@code username:password@} are optional. If given, the driver will attempt to login to a database after
+ * connecting to a database server.
+ * - {@code host1} is the only required part of the URI. It identifies a server address to connect to.
+ * - {@code :portX} is optional and defaults to :27017 if not provided.
+ * - {@code /database} is the name of the database to login to and thus is only relevant if the
+ * {@code username:password@} syntax is used. If not specified the "admin" database will be used by default.
+ * - {@code ?options} are connection options. Note that if {@code database} is absent there is still a {@code /}
+ * required between the last host and the {@code ?} introducing the options. Options are name=value pairs and the pairs
+ * are separated by "&". For backwards compatibility, ";" is accepted as a separator in addition to "&",
+ * but should be considered as deprecated.
+ *
+ *
+ * The Java driver supports the following options (case insensitive):
+ *
+ * Replica set configuration:
+ *
+ *
+ * - {@code replicaSet=name}: Implies that the hosts given are a seed list, and the driver will attempt to find
+ * all members of the set.
+ *
+ * Connection Configuration:
+ *
+ * - {@code ssl=true|false}: Whether to connect using SSL.
+ * - {@code connectTimeoutMS=ms}: How long a connection can take to be opened before timing out.
+ * - {@code socketTimeoutMS=ms}: How long a send or receive on a socket can take before timing out.
+ *
+ * Connection pool configuration:
+ *
+ * - {@code maxPoolSize=n}: The maximum number of connections in the connection pool.
+ * - {@code waitQueueMultiple=n} : this multiplier, multiplied with the maxPoolSize setting, gives the maximum number of
+ * threads that may be waiting for a connection to become available from the pool. All further threads will get an
+ * exception right away.
+ * - {@code waitQueueTimeoutMS=ms}: The maximum wait time in milliseconds that a thread may wait for a connection to
+ * become available.
+ *
+ * Write concern configuration:
+ *
+ * - {@code safe=true|false}
+ *
+ * - {@code true}: the driver sends a getLastError command after every update to ensure that the update succeeded
+ * (see also {@code w} and {@code wtimeoutMS}).
+ * - {@code false}: the driver does not send a getLastError command after every update.
+ *
+ *
+ * - {@code w=wValue}
+ *
+ * - The driver adds { w : wValue } to the getLastError command. Implies {@code safe=true}.
+ * - wValue is typically a number, but can be any string in order to allow for specifications like
+ * {@code "majority"}
+ *
+ *
+ * - {@code wtimeoutMS=ms}
+ *
+ * - The driver adds { wtimeout : ms } to the getlasterror command. Implies {@code safe=true}.
+ * - Used in combination with {@code w}
+ *
+ *
+ *
+ * Read preference configuration:
+ *
+ * - {@code slaveOk=true|false}: Whether a driver connected to a replica set will send reads to slaves/secondaries.
+ * - {@code readPreference=enum}: The read preference for this connection. If set, it overrides any slaveOk value.
+ *
+ * - Enumerated values:
+ *
+ * - {@code primary}
+ * - {@code primaryPreferred}
+ * - {@code secondary}
+ * - {@code secondaryPreferred}
+ * - {@code nearest}
+ *
+ *
+ *
+ *
+ * - {@code readPreferenceTags=string}. A representation of a tag set as a comma-separated list of colon-separated
+ * key-value pairs, e.g. {@code "dc:ny,rack:1}". Spaces are stripped from beginning and end of all keys and values.
+ * To specify a list of tag sets, using multiple readPreferenceTags,
+ * e.g. {@code readPreferenceTags=dc:ny,rack:1;readPreferenceTags=dc:ny;readPreferenceTags=}
+ *
+ * - Note the empty value for the last one, which means match any secondary as a last resort.
+ * - Order matters when using multiple readPreferenceTags.
+ *
+ *
+ *
+ * Authentication configuration:
+ *