/*
 * Copyright 2008-present 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.connection;

import com.mongodb.MongoException;
import com.mongodb.ReadPreference;
import com.mongodb.ServerAddress;
import com.mongodb.TagSet;
import com.mongodb.annotations.Immutable;
import com.mongodb.selector.ReadPreferenceServerSelector;
import com.mongodb.selector.WritableServerSelector;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

import static com.mongodb.assertions.Assertions.notNull;
import static java.lang.String.format;

Immutable snapshot state of a cluster.
Since:3.0
/** * Immutable snapshot state of a cluster. * * @since 3.0 */
@Immutable public class ClusterDescription { private final ClusterConnectionMode connectionMode; private final ClusterType type; private final List<ServerDescription> serverDescriptions; private final ClusterSettings clusterSettings; private final ServerSettings serverSettings; private final MongoException srvResolutionException;
Creates a new ClusterDescription.
Params:
  • connectionMode – whether to connect directly to a single server or to multiple servers
  • type – what sort of cluster this is
  • serverDescriptions – the descriptions of all the servers currently in this cluster
/** * Creates a new ClusterDescription. * * @param connectionMode whether to connect directly to a single server or to multiple servers * @param type what sort of cluster this is * @param serverDescriptions the descriptions of all the servers currently in this cluster */
public ClusterDescription(final ClusterConnectionMode connectionMode, final ClusterType type, final List<ServerDescription> serverDescriptions) { this(connectionMode, type, serverDescriptions, null, null); }
Creates a new ClusterDescription.
Params:
  • connectionMode – whether to connect directly to a single server or to multiple servers
  • type – what sort of cluster this is
  • serverDescriptions – the descriptions of all the servers currently in this cluster
  • clusterSettings – the cluster settings
  • serverSettings – the server settings
Since:3.4
/** * Creates a new ClusterDescription. * * @param connectionMode whether to connect directly to a single server or to multiple servers * @param type what sort of cluster this is * @param serverDescriptions the descriptions of all the servers currently in this cluster * @param clusterSettings the cluster settings * @param serverSettings the server settings * @since 3.4 */
public ClusterDescription(final ClusterConnectionMode connectionMode, final ClusterType type, final List<ServerDescription> serverDescriptions, final ClusterSettings clusterSettings, final ServerSettings serverSettings) { this(connectionMode, type, null, serverDescriptions, clusterSettings, serverSettings); }
Creates a new ClusterDescription.
Params:
  • connectionMode – whether to connect directly to a single server or to multiple servers
  • type – what sort of cluster this is
  • srvResolutionException – an exception resolving the SRV record
  • serverDescriptions – the descriptions of all the servers currently in this cluster
  • clusterSettings – the cluster settings
  • serverSettings – the server settings
Since:3.10
/** * Creates a new ClusterDescription. * * @param connectionMode whether to connect directly to a single server or to multiple servers * @param type what sort of cluster this is * @param srvResolutionException an exception resolving the SRV record * @param serverDescriptions the descriptions of all the servers currently in this cluster * @param clusterSettings the cluster settings * @param serverSettings the server settings * @since 3.10 */
public ClusterDescription(final ClusterConnectionMode connectionMode, final ClusterType type, final MongoException srvResolutionException, final List<ServerDescription> serverDescriptions, final ClusterSettings clusterSettings, final ServerSettings serverSettings) { notNull("all", serverDescriptions); this.connectionMode = notNull("connectionMode", connectionMode); this.type = notNull("type", type); this.srvResolutionException = srvResolutionException; this.serverDescriptions = new ArrayList<ServerDescription>(serverDescriptions); this.clusterSettings = clusterSettings; this.serverSettings = serverSettings; }
Gets the cluster settings, which may be null if not provided.
Returns:the cluster settings
Since:3.4
/** * Gets the cluster settings, which may be null if not provided. * * @return the cluster settings * @since 3.4 */
public ClusterSettings getClusterSettings() { return clusterSettings; }
Gets the server settings, which may be null if not provided.
Returns:the server settings
Since:3.4
/** * Gets the server settings, which may be null if not provided. * * @return the server settings * @since 3.4 */
public ServerSettings getServerSettings() { return serverSettings; }
Return whether all servers in the cluster are compatible with the driver.
Returns:true if all servers in the cluster are compatible with the driver
/** * Return whether all servers in the cluster are compatible with the driver. * * @return true if all servers in the cluster are compatible with the driver */
public boolean isCompatibleWithDriver() { for (ServerDescription cur : serverDescriptions) { if (!cur.isCompatibleWithDriver()) { return false; } } return true; }
Return a server in the cluster that is incompatibly older than the driver.
Returns:a server in the cluster that is incompatibly older than the driver, or null if there are none
Since:3.6
/** * Return a server in the cluster that is incompatibly older than the driver. * * @return a server in the cluster that is incompatibly older than the driver, or null if there are none * @since 3.6 */
public ServerDescription findServerIncompatiblyOlderThanDriver() { for (ServerDescription cur : serverDescriptions) { if (cur.isIncompatiblyOlderThanDriver()) { return cur; } } return null; }
Return a server in the cluster that is incompatibly newer than the driver.
Returns:a server in the cluster that is incompatibly newer than the driver, or null if there are none
Since:3.6
/** * Return a server in the cluster that is incompatibly newer than the driver. * * @return a server in the cluster that is incompatibly newer than the driver, or null if there are none * @since 3.6 */
public ServerDescription findServerIncompatiblyNewerThanDriver() { for (ServerDescription cur : serverDescriptions) { if (cur.isIncompatiblyNewerThanDriver()) { return cur; } } return null; }
Returns true if this cluster has at least one server that satisfies the given read preference.
Params:
  • readPreference – the non-null read preference
Returns:whether this cluster has at least one server that satisfies the given read preference
Since:3.3
/** * Returns true if this cluster has at least one server that satisfies the given read preference. * * @param readPreference the non-null read preference * @return whether this cluster has at least one server that satisfies the given read preference * @since 3.3 */
public boolean hasReadableServer(final ReadPreference readPreference) { notNull("readPreference", readPreference); return !new ReadPreferenceServerSelector(readPreference).select(this).isEmpty(); }
Returns true if this cluster has at least one server that can be used for write operations.
Returns:true if this cluster has at least one server that can be used for write operations
Since:3.3
/** * Returns true if this cluster has at least one server that can be used for write operations. * * @return true if this cluster has at least one server that can be used for write operations * @since 3.3 */
public boolean hasWritableServer() { return !new WritableServerSelector().select(this).isEmpty(); }
Gets whether this cluster is connecting to a single server or multiple servers.
Returns:the ClusterConnectionMode for this cluster
/** * Gets whether this cluster is connecting to a single server or multiple servers. * * @return the ClusterConnectionMode for this cluster */
public ClusterConnectionMode getConnectionMode() { return connectionMode; }
Gets the specific type of this cluster
Returns:a ClusterType enum representing the type of this cluster
/** * Gets the specific type of this cluster * * @return a ClusterType enum representing the type of this cluster */
public ClusterType getType() { return type; }
Gets any exception encountered while resolving the SRV record for the initial host.
Returns:any exception encountered while resolving the SRV record for the initial host, or null if none
Since:3.10
/** * Gets any exception encountered while resolving the SRV record for the initial host. * * @return any exception encountered while resolving the SRV record for the initial host, or null if none * @since 3.10 */
public MongoException getSrvResolutionException() { return srvResolutionException; }
Returns an unmodifiable list of the server descriptions in this cluster description.
Returns:an unmodifiable list of the server descriptions in this cluster description
Since:3.3
/** * Returns an unmodifiable list of the server descriptions in this cluster description. * * @return an unmodifiable list of the server descriptions in this cluster description * @since 3.3 */
public List<ServerDescription> getServerDescriptions() { return Collections.unmodifiableList(serverDescriptions); }
Gets the logical session timeout in minutes, or null if at least one of the known servers does not support logical sessions.
Returns:the logical session timeout in minutes, which may be null
@mongodb.server.release3.6
Since:3.6
/** * Gets the logical session timeout in minutes, or null if at least one of the known servers does not support logical sessions. * * @return the logical session timeout in minutes, which may be null * @mongodb.server.release 3.6 * @since 3.6 */
public Integer getLogicalSessionTimeoutMinutes() { Integer retVal = null; for (ServerDescription cur : getServersByPredicate(new Predicate() { @Override public boolean apply(final ServerDescription serverDescription) { return serverDescription.isPrimary() || serverDescription.isSecondary(); } })) { if (cur.getLogicalSessionTimeoutMinutes() == null) { return null; } if (retVal == null) { retVal = cur.getLogicalSessionTimeoutMinutes(); } else { retVal = Math.min(retVal, cur.getLogicalSessionTimeoutMinutes()); } } return retVal; }
Returns the Set of all server descriptions in this cluster, sorted by the String value of the ServerAddress of each one.
Returns:the set of server descriptions
Deprecated:Use getServerDescriptions() instead
/** * Returns the Set of all server descriptions in this cluster, sorted by the String value of the ServerAddress of each one. * * @return the set of server descriptions * @deprecated Use {@link #getServerDescriptions()} instead */
@Deprecated public Set<ServerDescription> getAll() { Set<ServerDescription> serverDescriptionSet = new TreeSet<ServerDescription>(new Comparator<ServerDescription>() { @Override public int compare(final ServerDescription o1, final ServerDescription o2) { int val = o1.getAddress().getHost().compareTo(o2.getAddress().getHost()); if (val != 0) { return val; } return integerCompare(o1.getAddress().getPort(), o2.getAddress().getPort()); } private int integerCompare(final int p1, final int p2) { return (p1 < p2) ? -1 : ((p1 == p2) ? 0 : 1); } }); serverDescriptionSet.addAll(serverDescriptions); return Collections.unmodifiableSet(serverDescriptionSet); }
Returns the ServerDescription for the server at the given address
Params:
  • serverAddress – the ServerAddress for a server in this cluster
Returns:the ServerDescription for this server
Deprecated:Replace with a filter on ServerDescription in the caller
/** * Returns the ServerDescription for the server at the given address * * @param serverAddress the ServerAddress for a server in this cluster * @return the ServerDescription for this server * @deprecated Replace with a filter on ServerDescription in the caller */
@Deprecated public ServerDescription getByServerAddress(final ServerAddress serverAddress) { for (final ServerDescription cur : serverDescriptions) { if (cur.isOk() && cur.getAddress().equals(serverAddress)) { return cur; } } return null; }
While it may seem counter-intuitive that a MongoDB cluster can have more than one primary, it can in the case where the client's view of the cluster is a set of mongos servers, any of which can serve as the primary.
Returns:a list of servers that can act as primaries
Deprecated:Replace with a filter on ServerDescription in the caller
/** * While it may seem counter-intuitive that a MongoDB cluster can have more than one primary, it can in the case where the client's view * of the cluster is a set of mongos servers, any of which can serve as the primary. * * @return a list of servers that can act as primaries * @deprecated Replace with a filter on ServerDescription in the caller */
@Deprecated public List<ServerDescription> getPrimaries() { return getServersByPredicate(new Predicate() { public boolean apply(final ServerDescription serverDescription) { return serverDescription.isPrimary(); } }); }
Get a list of all the secondaries in this cluster
Returns:a List of ServerDescriptions of all the secondaries this cluster is currently aware of
Deprecated:Replace with a filter on ServerDescription in the caller
/** * Get a list of all the secondaries in this cluster * * @return a List of ServerDescriptions of all the secondaries this cluster is currently aware of * @deprecated Replace with a filter on ServerDescription in the caller */
@Deprecated public List<ServerDescription> getSecondaries() { return getServersByPredicate(new Predicate() { public boolean apply(final ServerDescription serverDescription) { return serverDescription.isSecondary(); } }); }
Get a list of all the secondaries in this cluster that match a given TagSet
Params:
  • tagSet – a Set of replica set tags
Returns:a List of ServerDescriptions of all the secondaries this cluster that match all of the given tags
Deprecated:Replace with a filter on ServerDescription in the caller
/** * Get a list of all the secondaries in this cluster that match a given TagSet * * @param tagSet a Set of replica set tags * @return a List of ServerDescriptions of all the secondaries this cluster that match all of the given tags * @deprecated Replace with a filter on ServerDescription in the caller */
@Deprecated public List<ServerDescription> getSecondaries(final TagSet tagSet) { return getServersByPredicate(new Predicate() { public boolean apply(final ServerDescription serverDescription) { return serverDescription.isSecondary() && serverDescription.hasTags(tagSet); } }); }
Gets a list of ServerDescriptions for all the servers in this cluster which are currently accessible.
Returns:a List of ServerDescriptions for all servers that have a status of OK
Deprecated:Replace with a filter on ServerDescription in the caller
/** * Gets a list of ServerDescriptions for all the servers in this cluster which are currently accessible. * * @return a List of ServerDescriptions for all servers that have a status of OK * @deprecated Replace with a filter on ServerDescription in the caller */
@Deprecated public List<ServerDescription> getAny() { return getServersByPredicate(new Predicate() { public boolean apply(final ServerDescription serverDescription) { return serverDescription.isOk(); } }); }
Gets a list of all the primaries and secondaries in this cluster.
Returns:a list of ServerDescriptions for all primary and secondary servers
Deprecated:Replace with a filter on ServerDescription in the caller
/** * Gets a list of all the primaries and secondaries in this cluster. * * @return a list of ServerDescriptions for all primary and secondary servers * @deprecated Replace with a filter on ServerDescription in the caller */
@Deprecated public List<ServerDescription> getAnyPrimaryOrSecondary() { return getServersByPredicate(new Predicate() { public boolean apply(final ServerDescription serverDescription) { return serverDescription.isPrimary() || serverDescription.isSecondary(); } }); }
Gets a list of all the primaries and secondaries in this cluster that match the given replica set tags.
Params:
  • tagSet – a Set of replica set tags
Returns:a list of ServerDescriptions for all primary and secondary servers that contain all of the given tags
Deprecated:Replace with a filter on ServerDescription in the caller
/** * Gets a list of all the primaries and secondaries in this cluster that match the given replica set tags. * * @param tagSet a Set of replica set tags * @return a list of ServerDescriptions for all primary and secondary servers that contain all of the given tags * @deprecated Replace with a filter on ServerDescription in the caller */
@Deprecated public List<ServerDescription> getAnyPrimaryOrSecondary(final TagSet tagSet) { return getServersByPredicate(new Predicate() { public boolean apply(final ServerDescription serverDescription) { return (serverDescription.isPrimary() || serverDescription.isSecondary()) && serverDescription.hasTags(tagSet); } }); } @Override public boolean equals(final Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } ClusterDescription that = (ClusterDescription) o; if (connectionMode != that.connectionMode) { return false; } if (type != that.type) { return false; } if (serverDescriptions.size() != that.serverDescriptions.size()) { return false; } if (!serverDescriptions.containsAll(that.serverDescriptions)) { return false; } // Compare class equality and message as exceptions rarely override equals Class<?> thisExceptionClass = srvResolutionException != null ? srvResolutionException.getClass() : null; Class<?> thatExceptionClass = that.srvResolutionException != null ? that.srvResolutionException.getClass() : null; if (thisExceptionClass != null ? !thisExceptionClass.equals(thatExceptionClass) : thatExceptionClass != null) { return false; } String thisExceptionMessage = srvResolutionException != null ? srvResolutionException.getMessage() : null; String thatExceptionMessage = that.srvResolutionException != null ? that.srvResolutionException.getMessage() : null; if (thisExceptionMessage != null ? !thisExceptionMessage.equals(thatExceptionMessage) : thatExceptionMessage != null) { return false; } return true; } @Override public int hashCode() { int result = connectionMode.hashCode(); result = 31 * result + type.hashCode(); result = 31 * result + (srvResolutionException == null ? 0 : srvResolutionException.hashCode()); result = 31 * result + serverDescriptions.hashCode(); return result; } @Override public String toString() { return "ClusterDescription{" + "type=" + getType() + (srvResolutionException == null ? "" : ", srvResolutionException=" + srvResolutionException) + ", connectionMode=" + connectionMode + ", serverDescriptions=" + serverDescriptions + '}'; }
Returns a short, pretty description for this ClusterDescription.
Returns:a String describing this cluster.
/** * Returns a short, pretty description for this ClusterDescription. * * @return a String describing this cluster. */
public String getShortDescription() { StringBuilder serverDescriptions = new StringBuilder(); String delimiter = ""; for (final ServerDescription cur : this.serverDescriptions) { serverDescriptions.append(delimiter).append(cur.getShortDescription()); delimiter = ", "; } if (srvResolutionException == null) { return format("{type=%s, servers=[%s]", type, serverDescriptions); } else { return format("{type=%s, srvResolutionException=%s, servers=[%s]", type, srvResolutionException, serverDescriptions); } } private interface Predicate { boolean apply(ServerDescription serverDescription); } private List<ServerDescription> getServersByPredicate(final Predicate predicate) { List<ServerDescription> membersByTag = new ArrayList<ServerDescription>(); for (final ServerDescription cur : serverDescriptions) { if (predicate.apply(cur)) { membersByTag.add(cur); } } return membersByTag; } }