package com.mongodb.internal.connection;
import com.mongodb.ServerAddress;
import com.mongodb.Tag;
import com.mongodb.TagSet;
import com.mongodb.connection.ConnectionDescription;
import com.mongodb.connection.ConnectionId;
import com.mongodb.connection.ServerDescription;
import com.mongodb.connection.ServerType;
import com.mongodb.connection.ServerVersion;
import org.bson.BsonArray;
import org.bson.BsonBoolean;
import org.bson.BsonDocument;
import org.bson.BsonInt32;
import org.bson.BsonString;
import org.bson.BsonValue;
import org.bson.types.ObjectId;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static com.mongodb.connection.ConnectionDescription.getDefaultMaxMessageSize;
import static com.mongodb.connection.ConnectionDescription.getDefaultMaxWriteBatchSize;
import static com.mongodb.connection.ServerConnectionState.CONNECTED;
import static com.mongodb.connection.ServerDescription.getDefaultMaxDocumentSize;
import static com.mongodb.connection.ServerDescription.getDefaultMaxWireVersion;
import static com.mongodb.connection.ServerDescription.getDefaultMinWireVersion;
import static com.mongodb.connection.ServerType.REPLICA_SET_ARBITER;
import static com.mongodb.connection.ServerType.REPLICA_SET_OTHER;
import static com.mongodb.connection.ServerType.REPLICA_SET_PRIMARY;
import static com.mongodb.connection.ServerType.REPLICA_SET_SECONDARY;
import static com.mongodb.connection.ServerType.SHARD_ROUTER;
import static com.mongodb.connection.ServerType.STANDALONE;
import static com.mongodb.connection.ServerType.UNKNOWN;
import static java.util.Arrays.asList;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
public final class DescriptionHelper {
static ConnectionDescription createConnectionDescription(final ConnectionId connectionId,
final BsonDocument isMasterResult,
final BsonDocument buildInfoResult) {
ConnectionDescription connectionDescription = new ConnectionDescription(connectionId, getVersion(buildInfoResult),
getMaxWireVersion(isMasterResult), getServerType(isMasterResult), getMaxWriteBatchSize(isMasterResult),
getMaxBsonObjectSize(isMasterResult), getMaxMessageSizeBytes(isMasterResult), getCompressors(isMasterResult));
if (isMasterResult.containsKey("connectionId")) {
ConnectionId newConnectionId =
connectionDescription.getConnectionId().withServerValue(isMasterResult.getNumber("connectionId").intValue());
connectionDescription = connectionDescription.withConnectionId(newConnectionId);
}
return connectionDescription;
}
public static ServerDescription createServerDescription(final ServerAddress serverAddress, final BsonDocument isMasterResult,
final ServerVersion serverVersion, final long roundTripTime) {
return ServerDescription.builder()
.state(CONNECTED)
.version(serverVersion)
.address(serverAddress)
.type(getServerType(isMasterResult))
.canonicalAddress(isMasterResult.containsKey("me") ? isMasterResult.getString("me").getValue() : null)
.hosts(listToSet(isMasterResult.getArray("hosts", new BsonArray())))
.passives(listToSet(isMasterResult.getArray("passives", new BsonArray())))
.arbiters(listToSet(isMasterResult.getArray("arbiters", new BsonArray())))
.primary(getString(isMasterResult, "primary"))
.maxDocumentSize(getMaxBsonObjectSize(isMasterResult))
.tagSet(getTagSetFromDocument(isMasterResult.getDocument("tags", new BsonDocument())))
.setName(getString(isMasterResult, "setName"))
.minWireVersion(getMinWireVersion(isMasterResult))
.maxWireVersion(getMaxWireVersion(isMasterResult))
.electionId(getElectionId(isMasterResult))
.setVersion(getSetVersion(isMasterResult))
.lastWriteDate(getLastWriteDate(isMasterResult))
.roundTripTime(roundTripTime, NANOSECONDS)
.logicalSessionTimeoutMinutes(getLogicalSessionTimeoutMinutes(isMasterResult))
.ok(CommandHelper.isCommandOk(isMasterResult)).build();
}
private static int getMinWireVersion(final BsonDocument isMasterResult) {
return isMasterResult.getInt32("minWireVersion", new BsonInt32(getDefaultMinWireVersion())).getValue();
}
private static int getMaxWireVersion(final BsonDocument isMasterResult) {
return isMasterResult.getInt32("maxWireVersion", new BsonInt32(getDefaultMaxWireVersion())).getValue();
}
private static Date getLastWriteDate(final BsonDocument isMasterResult) {
if (!isMasterResult.containsKey("lastWrite")) {
return null;
}
return new Date(isMasterResult.getDocument("lastWrite").getDateTime("lastWriteDate").getValue());
}
private static ObjectId getElectionId(final BsonDocument isMasterResult) {
return isMasterResult.containsKey("electionId") ? isMasterResult.getObjectId("electionId").getValue() : null;
}
private static Integer getSetVersion(final BsonDocument isMasterResult) {
return isMasterResult.containsKey("setVersion") ? isMasterResult.getNumber("setVersion").intValue() : null;
}
private static int getMaxMessageSizeBytes(final BsonDocument isMasterResult) {
return isMasterResult.getInt32("maxMessageSizeBytes", new BsonInt32(getDefaultMaxMessageSize())).getValue();
}
private static int getMaxBsonObjectSize(final BsonDocument isMasterResult) {
return isMasterResult.getInt32("maxBsonObjectSize", new BsonInt32(getDefaultMaxDocumentSize())).getValue();
}
private static int getMaxWriteBatchSize(final BsonDocument isMasterResult) {
return isMasterResult.getInt32("maxWriteBatchSize", new BsonInt32(getDefaultMaxWriteBatchSize())).getValue();
}
private static Integer getLogicalSessionTimeoutMinutes(final BsonDocument isMasterResult) {
return isMasterResult.isNumber("logicalSessionTimeoutMinutes")
? isMasterResult.getNumber("logicalSessionTimeoutMinutes").intValue() : null;
}
private static String getString(final BsonDocument response, final String key) {
if (response.containsKey(key)) {
return response.getString(key).getValue();
} else {
return null;
}
}
static ServerVersion getVersion(final BsonDocument buildInfoResult) {
List<BsonValue> versionArray = buildInfoResult.getArray("versionArray").subList(0, 3);
return new ServerVersion(asList(versionArray.get(0).asInt32().getValue(),
versionArray.get(1).asInt32().getValue(),
versionArray.get(2).asInt32().getValue()));
}
private static Set<String> listToSet(final BsonArray array) {
if (array == null || array.isEmpty()) {
return Collections.emptySet();
} else {
Set<String> set = new HashSet<String>();
for (BsonValue value : array) {
set.add(value.asString().getValue());
}
return set;
}
}
private static ServerType getServerType(final BsonDocument isMasterResult) {
if (!CommandHelper.isCommandOk(isMasterResult)) {
return UNKNOWN;
}
if (isReplicaSetMember(isMasterResult)) {
if (isMasterResult.getBoolean("hidden", BsonBoolean.FALSE).getValue()) {
return REPLICA_SET_OTHER;
}
if (isMasterResult.getBoolean("ismaster", BsonBoolean.FALSE).getValue()) {
return REPLICA_SET_PRIMARY;
}
if (isMasterResult.getBoolean("secondary", BsonBoolean.FALSE).getValue()) {
return REPLICA_SET_SECONDARY;
}
if (isMasterResult.getBoolean("arbiterOnly", BsonBoolean.FALSE).getValue()) {
return REPLICA_SET_ARBITER;
}
if (isMasterResult.containsKey("setName") && isMasterResult.containsKey("hosts")) {
return ServerType.REPLICA_SET_OTHER;
}
return ServerType.REPLICA_SET_GHOST;
}
if (isMasterResult.containsKey("msg") && isMasterResult.get("msg").equals(new BsonString("isdbgrid"))) {
return SHARD_ROUTER;
}
return STANDALONE;
}
private static boolean isReplicaSetMember(final BsonDocument isMasterResult) {
return isMasterResult.containsKey("setName") || isMasterResult.getBoolean("isreplicaset", BsonBoolean.FALSE).getValue();
}
private static TagSet getTagSetFromDocument(final BsonDocument tagsDocuments) {
List<Tag> tagList = new ArrayList<Tag>();
for (final Map.Entry<String, BsonValue> curEntry : tagsDocuments.entrySet()) {
tagList.add(new Tag(curEntry.getKey(), curEntry.getValue().asString().getValue()));
}
return new TagSet(tagList);
}
private static List<String> getCompressors(final BsonDocument isMasterResult) {
List<String> compressorList = new ArrayList<String>();
for (BsonValue compressor : isMasterResult.getArray("compression", new BsonArray())) {
compressorList.add(compressor.asString().getValue());
}
return compressorList;
}
private DescriptionHelper() {
}
}