com.mongodb.Mongo Maven / Gradle / Ivy
Show all versions of mongo-java-driver Show documentation
/*
* Copyright (c) 2008-2015 MongoDB, 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.mongodb;
import com.mongodb.annotations.ThreadSafe;
import com.mongodb.binding.ClusterBinding;
import com.mongodb.binding.ConnectionSource;
import com.mongodb.binding.ReadBinding;
import com.mongodb.binding.ReadWriteBinding;
import com.mongodb.binding.SingleServerBinding;
import com.mongodb.binding.WriteBinding;
import com.mongodb.connection.BufferProvider;
import com.mongodb.connection.Cluster;
import com.mongodb.connection.ClusterConnectionMode;
import com.mongodb.connection.ClusterDescription;
import com.mongodb.connection.ClusterSettings;
import com.mongodb.connection.Connection;
import com.mongodb.connection.DefaultClusterFactory;
import com.mongodb.connection.ServerDescription;
import com.mongodb.connection.SocketStreamFactory;
import com.mongodb.event.CommandListener;
import com.mongodb.event.CommandListenerMulticaster;
import com.mongodb.internal.connection.PowerOfTwoBufferPool;
import com.mongodb.management.JMXConnectionPoolListener;
import com.mongodb.operation.ListDatabasesOperation;
import com.mongodb.operation.OperationExecutor;
import com.mongodb.operation.ReadOperation;
import com.mongodb.operation.WriteOperation;
import com.mongodb.selector.LatencyMinimizingServerSelector;
import com.mongodb.selector.ServerSelector;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
import static com.mongodb.ReadPreference.primary;
import static com.mongodb.connection.ClusterConnectionMode.MULTIPLE;
import static com.mongodb.connection.ClusterType.REPLICA_SET;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
import static java.util.Collections.unmodifiableList;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.SECONDS;
/**
* A database connection with internal connection pooling. For most applications, you should have one Mongo instance for the entire
* JVM.
*
* Note: This class has been superseded by {@code MongoClient}, and may be deprecated in a future release.
*
* @see MongoClient
* @see ReadPreference
* @see WriteConcern
*/
@ThreadSafe
public class Mongo {
static final String ADMIN_DATABASE_NAME = "admin";
private final ConcurrentMap dbCache = new ConcurrentHashMap();
private volatile WriteConcern writeConcern;
private volatile ReadPreference readPreference;
private final MongoClientOptions options;
private final List credentialsList;
private final Bytes.OptionHolder optionHolder;
private final Cluster cluster;
private final BufferProvider bufferProvider = new PowerOfTwoBufferPool();
private final ConcurrentLinkedQueue orphanedCursors = new ConcurrentLinkedQueue();
private final ExecutorService cursorCleaningService;
/**
* Creates a Mongo instance based on a (single) mongodb node (localhost, default port)
*
* @throws MongoException if there's a failure
* @deprecated Replaced by {@link MongoClient#MongoClient()})
*/
@Deprecated
public Mongo() {
this(new ServerAddress(), createLegacyOptions());
}
/**
* Creates a Mongo instance based on a (single) mongodb node (default port)
*
* @param host server to connect to
* @deprecated Replaced by {@link MongoClient#MongoClient(String)}
*/
@Deprecated
public Mongo(final String host) {
this(new ServerAddress(host), createLegacyOptions());
}
/**
* Creates a Mongo instance based on a (single) mongodb node (default port)
*
* @param host server to connect to
* @param options default query options
* @deprecated Replaced by {@link MongoClient#MongoClient(String, MongoClientOptions)}
*/
@Deprecated
public Mongo(final String host,
@SuppressWarnings("deprecation")
final MongoOptions options) {
this(new ServerAddress(host), options.toClientOptions());
}
/**
* Creates a Mongo instance based on a (single) mongodb node
*
* @param host the host address of the database
* @param port the port on which the database is running
* @deprecated Replaced by {@link MongoClient#MongoClient(String, int)}
*/
@Deprecated
public Mongo(final String host, final int port) {
this(new ServerAddress(host, port), createLegacyOptions());
}
/**
* Creates a Mongo instance based on a (single) mongodb node
*
* @param address the database address
* @see com.mongodb.ServerAddress
* @deprecated Replaced by {@link MongoClient#MongoClient(ServerAddress)}
*/
@Deprecated
public Mongo(final ServerAddress address) {
this(address, createLegacyOptions());
}
/**
* Creates a Mongo instance based on a (single) mongo node using a given ServerAddress
*
* @param address the database address
* @param options default query options
* @see com.mongodb.ServerAddress
* @deprecated Replaced by {@link MongoClient#MongoClient(ServerAddress, MongoClientOptions)}
*/
@Deprecated
public Mongo(final ServerAddress address,
@SuppressWarnings("deprecation")
final MongoOptions options) {
this(address, options.toClientOptions());
}
/**
* Creates a Mongo in paired mode.
*
* This will also work for a replica set and will find all members (the master will be used by default).
*
* @param left left side of the pair
* @param right right side of the pair
* @see com.mongodb.ServerAddress
* @deprecated Please use {@link MongoClient#MongoClient(java.util.List)} instead.
*/
@Deprecated
public Mongo(final ServerAddress left, final ServerAddress right) {
this(asList(left, right), createLegacyOptions());
}
/**
* Creates a Mongo connection in paired mode.
*
* This will also work for a replica set and will find all members (the master will be used by default).
*
* @param left left side of the pair
* @param right right side of the pair
* @param options the optional settings for the Mongo instance
* @see com.mongodb.ServerAddress
* @deprecated Please use {@link MongoClient#MongoClient(java.util.List, MongoClientOptions)} instead.
*/
@Deprecated
public Mongo(final ServerAddress left, final ServerAddress right,
@SuppressWarnings("deprecation")
final MongoOptions options) {
this(asList(left, right), options.toClientOptions());
}
/**
* 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.
* @see com.mongodb.ServerAddress
* @deprecated Replaced by {@link MongoClient#MongoClient(java.util.List)}
*/
@Deprecated
public Mongo(final List seeds) {
this(seeds, createLegacyOptions());
}
/**
* 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 for configuring this Mongo instance
* @see com.mongodb.ServerAddress
* @deprecated Replaced by {@link MongoClient#MongoClient(java.util.List, MongoClientOptions)}
*/
@Deprecated
public Mongo(final List seeds,
@SuppressWarnings("deprecation")
final MongoOptions options) {
this(seeds, options.toClientOptions());
}
/**
* 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.
*
* Examples:
*
* - mongodb://localhost
* - mongodb://fred:foobar@localhost/
*
*
* @param uri URI to connect to, optionally containing additional information like credentials
* @throws MongoException if there's a failure
* @mongodb.driver.manual reference/connection-string Connection String URI Format
* @see MongoURI
* @deprecated Replaced by {@link MongoClient#MongoClient(MongoClientURI)}
*/
@Deprecated
public Mongo(
@SuppressWarnings("deprecation")
final MongoURI uri) {
this(uri.toClientURI());
}
Mongo(final List seedList, final MongoClientOptions options) {
this(seedList, Collections.emptyList(), options);
}
Mongo(final ServerAddress serverAddress, final MongoClientOptions options) {
this(serverAddress, Collections.emptyList(), options);
}
Mongo(final ServerAddress serverAddress, final List credentialsList, final MongoClientOptions options) {
this(createCluster(serverAddress, credentialsList, options), options, credentialsList);
}
Mongo(final List seedList, final List credentialsList, final MongoClientOptions options) {
this(createCluster(seedList, credentialsList, options), options, credentialsList);
}
Mongo(final MongoClientURI mongoURI) {
this(createCluster(mongoURI),
mongoURI.getOptions(),
mongoURI.getCredentials() != null ? asList(mongoURI.getCredentials()) : Collections.emptyList());
}
Mongo(final Cluster cluster, final MongoClientOptions options, final List credentialsList) {
this.cluster = cluster;
this.options = options;
this.readPreference = options.getReadPreference() != null ? options.getReadPreference() : primary();
this.writeConcern = options.getWriteConcern() != null ? options.getWriteConcern() : WriteConcern.UNACKNOWLEDGED;
this.optionHolder = new Bytes.OptionHolder(null);
this.credentialsList = unmodifiableList(credentialsList);
cursorCleaningService = options.isCursorFinalizerEnabled() ? createCursorCleaningService() : null;
}
/**
* Sets the write concern for this database. Will be used as default for writes to any collection in any database. See the documentation
* for {@link WriteConcern} for more information.
*
* @param writeConcern write concern to use
*/
public void setWriteConcern(final WriteConcern writeConcern) {
this.writeConcern = writeConcern;
}
/**
* Gets the default write concern
*
* @return the default write concern
*/
public WriteConcern getWriteConcern() {
return writeConcern;
}
/**
* Sets the read preference for this database. Will be used as default for reads from any collection in any database. See the
* documentation for {@link ReadPreference} for more information.
*
* @param readPreference Read Preference to use
*/
public void setReadPreference(final ReadPreference readPreference) {
this.readPreference = readPreference;
}
/**
* Gets the default read preference
*
* @return the default read preference
*/
public ReadPreference getReadPreference() {
return readPreference;
}
/**
* Gets a list of all server addresses used when this Mongo was created
*
* @return list of server addresses
* @throws MongoException if there's a failure
*/
public List getAllAddress() {
//TODO It should return the address list without auto-discovered nodes. Not sure if it's required. Maybe users confused with name.
return getServerAddressList();
}
/**
* Gets the list of server addresses currently seen by this client. This includes addresses auto-discovered from a replica set.
*
* @return list of server addresses
* @throws MongoException if there's a failure
*/
public List getServerAddressList() {
List serverAddresses = new ArrayList();
for (final ServerDescription cur : getClusterDescription().getAll()) {
serverAddresses.add(cur.getAddress());
}
return serverAddresses;
}
private ClusterDescription getClusterDescription() {
return cluster.getDescription();
}
/**
* Gets the address of the current master
*
* @return the address
*/
public ServerAddress getAddress() {
ClusterDescription description = getClusterDescription();
if (description.getPrimaries().isEmpty()) {
return null;
}
return description.getPrimaries().get(0).getAddress();
}
/**
* Returns the mongo options.
*
* Changes to {@code MongoOptions} that are done after connection are not reflected.
*
* @return the mongo options
* @deprecated Please use {@link MongoClient} class to connect to server and corresponding {@link
* com.mongodb.MongoClient#getMongoClientOptions()}
*/
@Deprecated
public MongoOptions getMongoOptions() {
return new MongoOptions(getMongoClientOptions());
}
/**
* Get the status of the replica set cluster.
*
* @return replica set status information
*/
public ReplicaSetStatus getReplicaSetStatus() {
ClusterDescription clusterDescription = getClusterDescription();
return clusterDescription.getType() == REPLICA_SET && clusterDescription.getConnectionMode() == MULTIPLE
? new ReplicaSetStatus(cluster) : null; // this is intended behavior in 2.x
}
/**
* Gets a list of the names of all databases on the connected server.
*
* @return list of database names
* @throws MongoException if the operation fails
* @deprecated Replaced with {@link com.mongodb.MongoClient#listDatabaseNames()}
*/
@Deprecated
public List getDatabaseNames() {
return new OperationIterable(new ListDatabasesOperation(MongoClient.getCommandCodec()),
primary(), createOperationExecutor())
.map(new Function() {
@Override
public String apply(final DBObject result) {
return (String) result.get("name");
}
}).into(new ArrayList());
}
/**
* Gets a database object. Users should use {@link com.mongodb.MongoClient#getDatabase(String)} instead.
*
*
* The {@link DB} class has been superseded by {@link com.mongodb.client.MongoDatabase}. The deprecation of this method effectively
* deprecates the {@link DB}, {@link DBCollection}, and {@link DBCursor} classes, among others; but in order to give users time to
* migrate to the new API without experiencing a huge number of compiler warnings, those classes have not yet been formally
* deprecated.
*
*
* @param dbName the name of the database to retrieve
* @return a DB representing the specified database
* @deprecated use {@link com.mongodb.MongoClient#getDatabase(String)}
*/
@Deprecated
public DB getDB(final String dbName) {
DB db = dbCache.get(dbName);
if (db != null) {
return db;
}
db = new DB(this, dbName, createOperationExecutor());
DB temp = dbCache.putIfAbsent(dbName, db);
if (temp != null) {
return temp;
}
return db;
}
/**
* Returns the list of databases used by the driver since this Mongo instance was created. This may include DBs that exist in the client
* but not yet on the server.
*
* @return a collection of database objects
*/
public Collection getUsedDatabases() {
return dbCache.values();
}
/**
* Drops the database if it exists.
*
* @param dbName name of database to drop
* @throws MongoException if the operation fails
*/
public void dropDatabase(final String dbName) {
getDB(dbName).dropDatabase();
}
/**
* Closes all resources associated with this instance, in particular any open network connections. Once called, this instance and any
* databases obtained from it can no longer be used.
*/
public void close() {
cluster.close();
if (cursorCleaningService != null) {
cursorCleaningService.shutdownNow();
}
}
/**
* Makes it possible to run read queries on secondary nodes
*
* @see ReadPreference#secondaryPreferred()
* @deprecated Replaced with {@code ReadPreference.secondaryPreferred()}
*/
@Deprecated
public void slaveOk() {
addOption(Bytes.QUERYOPTION_SLAVEOK);
}
/**
* Set the default query options.
*
* @param options value to be set
*/
public void setOptions(final int options) {
optionHolder.set(options);
}
/**
* Reset the default query options.
*/
public void resetOptions() {
optionHolder.reset();
}
/**
* Add the default query option.
*
* @param option value to be added to current options
*/
public void addOption(final int option) {
optionHolder.add(option);
}
/**
* Gets the default query options
*
* @return an int representing the options to be used by queries
*/
public int getOptions() {
return optionHolder.get();
}
/**
* 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 result of the command execution
* @throws MongoException if there's a failure
* @mongodb.driver.manual reference/command/fsync/ fsync command
*/
public CommandResult fsync(final boolean async) {
DBObject command = new BasicDBObject("fsync", 1);
if (async) {
command.put("async", 1);
}
return getDB(ADMIN_DATABASE_NAME).command(command);
}
/**
* 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 result of the command execution
* @throws MongoException if there's a failure
* @mongodb.driver.manual reference/command/fsync/ fsync command
*/
public CommandResult fsyncAndLock() {
DBObject command = new BasicDBObject("fsync", 1);
command.put("lock", 1);
return getDB(ADMIN_DATABASE_NAME).command(command);
}
/**
* 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 {@code DBObject} in the following form {@code {"ok": 1,"info": "unlock completed"}}
* @throws MongoException if there's a failure
* @mongodb.driver.manual reference/command/fsync/ fsync command
*/
public DBObject unlock() {
return getDB(ADMIN_DATABASE_NAME).getCollection("$cmd.sys.unlock").findOne();
}
/**
* Returns true if the database is locked (read-only), false otherwise.
*
* @return result of the command execution
* @throws MongoException if the operation fails
* @mongodb.driver.manual reference/command/fsync/ fsync command
*/
public boolean isLocked() {
DBCollection inprogCollection = getDB(ADMIN_DATABASE_NAME).getCollection("$cmd.sys.inprog");
BasicDBObject result = (BasicDBObject) inprogCollection.findOne();
return result.containsField("fsyncLock") && result.getInt("fsyncLock") == 1;
}
@Override
public String toString() {
return "Mongo{"
+ "options=" + getMongoClientOptions()
+ '}';
}
/**
* Gets the maximum size for a BSON object supported by the current master server. Note that this value may change over time depending
* on which server is master.
*
* @return the maximum size, or 0 if not obtained from servers yet.
* @throws MongoException if there's a failure
*/
public int getMaxBsonObjectSize() {
List primaries = getClusterDescription().getPrimaries();
return primaries.isEmpty() ? ServerDescription.getDefaultMaxDocumentSize() : primaries.get(0).getMaxDocumentSize();
}
/**
* Gets a {@code String} representation of current connection point, i.e. master.
*
* @return server address in a host:port form
*/
public String getConnectPoint() {
ServerAddress master = getAddress();
return master != null ? String.format("%s:%d", master.getHost(), master.getPort()) : null;
}
private static MongoClientOptions createLegacyOptions() {
return MongoClientOptions.builder()
.legacyDefaults()
.build();
}
private static Cluster createCluster(final MongoClientURI mongoURI) {
List credentialList = mongoURI.getCredentials() != null
? asList(mongoURI.getCredentials())
: Collections.emptyList();
if (mongoURI.getHosts().size() == 1) {
return createCluster(new ServerAddress(mongoURI.getHosts().get(0)),
credentialList,
mongoURI.getOptions());
} else {
List seedList = new ArrayList(mongoURI.getHosts().size());
for (final String host : mongoURI.getHosts()) {
seedList.add(new ServerAddress(host));
}
return createCluster(seedList, credentialList, mongoURI.getOptions());
}
}
private static Cluster createCluster(final List seedList,
final List credentialsList, final MongoClientOptions options) {
return createCluster(ClusterSettings.builder().hosts(createNewSeedList(seedList))
.requiredReplicaSetName(options.getRequiredReplicaSetName())
.serverSelectionTimeout(options.getServerSelectionTimeout(), MILLISECONDS)
.serverSelector(createServerSelector(options))
.description(options.getDescription())
.maxWaitQueueSize(options.getConnectionPoolSettings().getMaxWaitQueueSize())
.build(),
credentialsList, options);
}
private static Cluster createCluster(final ServerAddress serverAddress, final List credentialsList,
final MongoClientOptions options) {
return createCluster(ClusterSettings.builder()
.mode(getSingleServerClusterMode(options))
.hosts(asList(serverAddress))
.requiredReplicaSetName(options.getRequiredReplicaSetName())
.serverSelectionTimeout(options.getServerSelectionTimeout(), MILLISECONDS)
.serverSelector(createServerSelector(options))
.description(options.getDescription())
.maxWaitQueueSize(options.getConnectionPoolSettings().getMaxWaitQueueSize())
.build(),
credentialsList, options);
}
private static Cluster createCluster(final ClusterSettings settings, final List credentialsList,
final MongoClientOptions options) {
return new DefaultClusterFactory().create(settings,
options.getServerSettings(),
options.getConnectionPoolSettings(),
new SocketStreamFactory(options.getSocketSettings(),
options.getSslSettings(),
options.getSocketFactory()),
new SocketStreamFactory(options.getHeartbeatSocketSettings(),
options.getSslSettings(),
options.getSocketFactory()),
credentialsList,
null, new JMXConnectionPoolListener(), null,
createCommandListener(options.getCommandListeners()));
}
private static CommandListener createCommandListener(final List commandListeners) {
switch (commandListeners.size()) {
case 0:
return null;
case 1:
return commandListeners.get(0);
default:
return new CommandListenerMulticaster(commandListeners);
}
}
private static List createNewSeedList(final List seedList) {
List retVal = new ArrayList(seedList.size());
for (final ServerAddress cur : seedList) {
retVal.add(cur);
}
return retVal;
}
private static ServerSelector createServerSelector(final MongoClientOptions options) {
return new LatencyMinimizingServerSelector(options.getLocalThreshold(), MILLISECONDS);
}
Cluster getCluster() {
return cluster;
}
Bytes.OptionHolder getOptionHolder() {
return optionHolder;
}
BufferProvider getBufferProvider() {
return bufferProvider;
}
MongoClientOptions getMongoClientOptions() {
return options;
}
List getCredentialsList() {
return credentialsList;
}
WriteBinding getWriteBinding() {
return getReadWriteBinding(primary());
}
ReadBinding getReadBinding(final ReadPreference readPreference) {
return getReadWriteBinding(readPreference);
}
private ReadWriteBinding getReadWriteBinding(final ReadPreference readPreference) {
return new ClusterBinding(getCluster(), readPreference);
}
void addOrphanedCursor(final ServerCursor serverCursor, final MongoNamespace namespace) {
orphanedCursors.add(new ServerCursorAndNamespace(serverCursor, namespace));
}
OperationExecutor createOperationExecutor() {
return new OperationExecutor() {
@Override
public T execute(final ReadOperation operation, final ReadPreference readPreference) {
return Mongo.this.execute(operation, readPreference);
}
@Override
public T execute(final WriteOperation operation) {
return Mongo.this.execute(operation);
}
};
}
T execute(final ReadOperation operation, final ReadPreference readPreference) {
ReadBinding binding = getReadBinding(readPreference);
try {
return operation.execute(binding);
} finally {
binding.release();
}
}
T execute(final WriteOperation operation) {
WriteBinding binding = getWriteBinding();
try {
return operation.execute(binding);
} finally {
binding.release();
}
}
private ExecutorService createCursorCleaningService() {
ScheduledExecutorService newTimer = Executors.newSingleThreadScheduledExecutor(new DaemonThreadFactory());
newTimer.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
cleanCursors();
}
}, 1, 1, SECONDS);
return newTimer;
}
private void cleanCursors() {
ServerCursorAndNamespace cur;
while ((cur = orphanedCursors.poll()) != null) {
ReadWriteBinding binding = new SingleServerBinding(cluster, cur.serverCursor.getAddress());
try {
ConnectionSource source = binding.getReadConnectionSource();
try {
Connection connection = source.getConnection();
try {
connection.killCursor(cur.namespace, singletonList(cur.serverCursor.getId()));
} finally {
connection.release();
}
} finally {
source.release();
}
} finally {
binding.release();
}
}
}
private static ClusterConnectionMode getSingleServerClusterMode(final MongoClientOptions options) {
if (options.getRequiredReplicaSetName() == null) {
return ClusterConnectionMode.SINGLE;
} else {
return ClusterConnectionMode.MULTIPLE;
}
}
private static class ServerCursorAndNamespace {
private final ServerCursor serverCursor;
private final MongoNamespace namespace;
public ServerCursorAndNamespace(final ServerCursor serverCursor, final MongoNamespace namespace) {
this.serverCursor = serverCursor;
this.namespace = namespace;
}
}
/**
* Mongo.Holder can be used as a static place to hold several instances of Mongo. Security is not enforced at this level, and needs to
* be done on the application side.
*/
public static class Holder {
private static final Holder INSTANCE = new Holder();
private final ConcurrentMap clients = new ConcurrentHashMap();
/**
* Get the only instance of {@code Holder}.
*
* @return the singleton instance of {@code Holder}
*/
public static Holder singleton() {
return INSTANCE;
}
/**
* Attempts to find an existing MongoClient instance matching that URI in the holder, and returns it if exists. Otherwise creates a
* new Mongo instance based on this URI and adds it to the holder.
*
* @param uri the Mongo URI
* @return the client
* @throws MongoException if there's a failure
* @deprecated Please use {@link #connect(MongoClientURI)} instead.
*/
@Deprecated
public Mongo connect(final MongoURI uri) {
return connect(uri.toClientURI());
}
/**
* Attempts to find an existing MongoClient instance matching that URI in the holder, and returns it if exists. Otherwise creates a
* new Mongo instance based on this URI and adds it to the holder.
*
* @param uri the Mongo URI
* @return the client
* @throws MongoException if there's a failure
*/
public Mongo connect(final MongoClientURI uri) {
String key = toKey(uri);
Mongo client = clients.get(key);
if (client == null) {
Mongo newbie = new MongoClient(uri);
client = clients.putIfAbsent(key, newbie);
if (client == null) {
client = newbie;
} else {
newbie.close();
}
}
return client;
}
private String toKey(final MongoClientURI uri) {
return uri.toString();
}
}
// Custom thread factory for scheduled executor service that creates daemon threads. Otherwise,
// applications that neglect to close MongoClient will not exit.
static class DaemonThreadFactory implements ThreadFactory {
private static final AtomicInteger poolNumber = new AtomicInteger(1);
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix;
DaemonThreadFactory() {
namePrefix = "pool-" + poolNumber.getAndIncrement() + "-thread-";
}
public Thread newThread(final Runnable runnable) {
Thread t = new Thread(runnable, namePrefix + threadNumber.getAndIncrement());
t.setDaemon(true);
return t;
}
}
}