/* * Decompiled with CFR 0.152. * * Could not load the following classes: * com.mongodb.AuthenticationMechanism * com.mongodb.ConnectionString$1 * com.mongodb.MongoCompressor * com.mongodb.MongoConfigurationException * com.mongodb.MongoCredential * com.mongodb.MongoNamespace * com.mongodb.ReadConcern * com.mongodb.ReadConcernLevel * com.mongodb.ReadPreference * com.mongodb.Tag * com.mongodb.TagSet * com.mongodb.WriteConcern * com.mongodb.diagnostics.logging.Logger * com.mongodb.diagnostics.logging.Loggers * com.mongodb.internal.dns.DefaultDnsResolver * com.mongodb.lang.Nullable * java.io.UnsupportedEncodingException * java.lang.Boolean * java.lang.CharSequence * java.lang.IllegalArgumentException * java.lang.Integer * java.lang.NumberFormatException * java.lang.Object * java.lang.String * java.lang.UnsupportedOperationException * java.net.URLDecoder * java.nio.charset.StandardCharsets * java.util.ArrayList * java.util.Arrays * java.util.Collection * java.util.Collections * java.util.HashMap * java.util.HashSet * java.util.LinkedHashSet * java.util.List * java.util.Map * java.util.Map$Entry * java.util.Objects * java.util.Set * java.util.concurrent.TimeUnit * org.bson.UuidRepresentation */ package com.mongodb; import com.mongodb.AuthenticationMechanism; import com.mongodb.ConnectionString; import com.mongodb.MongoCompressor; import com.mongodb.MongoConfigurationException; import com.mongodb.MongoCredential; import com.mongodb.MongoNamespace; import com.mongodb.ReadConcern; import com.mongodb.ReadConcernLevel; import com.mongodb.ReadPreference; import com.mongodb.Tag; import com.mongodb.TagSet; import com.mongodb.WriteConcern; import com.mongodb.diagnostics.logging.Logger; import com.mongodb.diagnostics.logging.Loggers; import com.mongodb.internal.dns.DefaultDnsResolver; import com.mongodb.lang.Nullable; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.concurrent.TimeUnit; import org.bson.UuidRepresentation; public class ConnectionString { private static final String MONGODB_PREFIX = "mongodb://"; private static final String MONGODB_SRV_PREFIX = "mongodb+srv://"; private static final Set ALLOWED_OPTIONS_IN_TXT_RECORD = new HashSet((Collection)Arrays.asList((Object[])new String[]{"authsource", "replicaset", "loadbalanced"})); private static final Logger LOGGER = Loggers.getLogger((String)"uri"); private final MongoCredential credential; private final boolean isSrvProtocol; private final List hosts; private final String database; private final String collection; private final String connectionString; private Integer srvMaxHosts; private String srvServiceName; private Boolean directConnection; private Boolean loadBalanced; private ReadPreference readPreference; private WriteConcern writeConcern; private Boolean retryWrites; private Boolean retryReads; private ReadConcern readConcern; private Integer minConnectionPoolSize; private Integer maxConnectionPoolSize; private Integer maxWaitTime; private Integer maxConnectionIdleTime; private Integer maxConnectionLifeTime; private Integer maxConnecting; private Integer connectTimeout; private Integer socketTimeout; private Boolean sslEnabled; private Boolean sslInvalidHostnameAllowed; private String requiredReplicaSetName; private Integer serverSelectionTimeout; private Integer localThreshold; private Integer heartbeatFrequency; private String applicationName; private List compressorList; private UuidRepresentation uuidRepresentation; private static final Set GENERAL_OPTIONS_KEYS = new LinkedHashSet(); private static final Set AUTH_KEYS = new HashSet(); private static final Set READ_PREFERENCE_KEYS = new HashSet(); private static final Set WRITE_CONCERN_KEYS = new HashSet(); private static final Set COMPRESSOR_KEYS = new HashSet(); private static final Set ALL_KEYS = new HashSet(); private static final Set TRUE_VALUES; private static final Set FALSE_VALUES; public ConnectionString(String connectionString) { String nsPart; String hostIdentifier; String userAndHostInformation; this.connectionString = connectionString; boolean isMongoDBProtocol = connectionString.startsWith(MONGODB_PREFIX); this.isSrvProtocol = connectionString.startsWith(MONGODB_SRV_PREFIX); if (!isMongoDBProtocol && !this.isSrvProtocol) { throw new IllegalArgumentException(String.format((String)"The connection string is invalid. Connection strings must start with either '%s' or '%s", (Object[])new Object[]{MONGODB_PREFIX, MONGODB_SRV_PREFIX})); } String unprocessedConnectionString = isMongoDBProtocol ? connectionString.substring(MONGODB_PREFIX.length()) : connectionString.substring(MONGODB_SRV_PREFIX.length()); int idx = unprocessedConnectionString.indexOf("/"); if (idx == -1) { if (unprocessedConnectionString.contains((CharSequence)"?")) { throw new IllegalArgumentException("The connection string contains options without trailing slash"); } userAndHostInformation = unprocessedConnectionString; unprocessedConnectionString = ""; } else { userAndHostInformation = unprocessedConnectionString.substring(0, idx); unprocessedConnectionString = unprocessedConnectionString.substring(idx + 1); } String userName = null; char[] password = null; idx = userAndHostInformation.lastIndexOf("@"); if (idx > 0) { String userInfo = userAndHostInformation.substring(0, idx).replace((CharSequence)"+", (CharSequence)"%2B"); hostIdentifier = userAndHostInformation.substring(idx + 1); int colonCount = this.countOccurrences(userInfo, ":"); if (userInfo.contains((CharSequence)"@") || colonCount > 1) { throw new IllegalArgumentException("The connection string contains invalid user information. If the username or password contains a colon (:) or an at-sign (@) then it must be urlencoded"); } if (colonCount == 0) { userName = this.urldecode(userInfo); } else { idx = userInfo.indexOf(":"); if (idx == 0) { throw new IllegalArgumentException("No username is provided in the connection string"); } userName = this.urldecode(userInfo.substring(0, idx)); password = this.urldecode(userInfo.substring(idx + 1), true).toCharArray(); } } else { if (idx == 0) { throw new IllegalArgumentException("The connection string contains an at-sign (@) without a user name"); } hostIdentifier = userAndHostInformation; } List unresolvedHosts = Collections.unmodifiableList(this.parseHosts((List)Arrays.asList((Object[])hostIdentifier.split(",")))); if (this.isSrvProtocol) { if (unresolvedHosts.size() > 1) { throw new IllegalArgumentException("Only one host allowed when using mongodb+srv protocol"); } if (((String)unresolvedHosts.get(0)).contains((CharSequence)":")) { throw new IllegalArgumentException("Host for when using mongodb+srv protocol can not contain a port"); } } this.hosts = unresolvedHosts; idx = unprocessedConnectionString.indexOf("?"); if (idx == -1) { nsPart = unprocessedConnectionString; unprocessedConnectionString = ""; } else { nsPart = unprocessedConnectionString.substring(0, idx); unprocessedConnectionString = unprocessedConnectionString.substring(idx + 1); } if (nsPart.length() > 0) { idx = (nsPart = this.urldecode(nsPart)).indexOf("."); if (idx < 0) { this.database = nsPart; this.collection = null; } else { this.database = nsPart.substring(0, idx); this.collection = nsPart.substring(idx + 1); } MongoNamespace.checkDatabaseNameValidity((String)this.database); } else { this.database = null; this.collection = null; } String txtRecordsQueryParameters = this.isSrvProtocol ? new DefaultDnsResolver().resolveAdditionalQueryParametersFromTxtRecords((String)unresolvedHosts.get(0)) : ""; String connectionStringQueryParamenters = unprocessedConnectionString; Map> connectionStringOptionsMap = this.parseOptions(connectionStringQueryParamenters); Map> txtRecordsOptionsMap = this.parseOptions(txtRecordsQueryParameters); if (!ALLOWED_OPTIONS_IN_TXT_RECORD.containsAll((Collection)txtRecordsOptionsMap.keySet())) { throw new MongoConfigurationException(String.format((String)"A TXT record is only permitted to contain the keys %s, but the TXT record for '%s' contains the keys %s", (Object[])new Object[]{ALLOWED_OPTIONS_IN_TXT_RECORD, unresolvedHosts.get(0), txtRecordsOptionsMap.keySet()})); } Map> combinedOptionsMaps = this.combineOptionsMaps(txtRecordsOptionsMap, connectionStringOptionsMap); if (this.isSrvProtocol && !combinedOptionsMaps.containsKey((Object)"ssl")) { combinedOptionsMaps.put((Object)"ssl", (Object)Collections.singletonList((Object)"true")); } this.translateOptions(combinedOptionsMaps); if (!this.isSrvProtocol && this.srvMaxHosts != null) { throw new IllegalArgumentException("srvMaxHosts can only be specified with mongodb+srv protocol"); } if (!this.isSrvProtocol && this.srvServiceName != null) { throw new IllegalArgumentException("srvServiceName can only be specified with mongodb+srv protocol"); } if (this.directConnection != null && this.directConnection.booleanValue()) { if (this.isSrvProtocol) { throw new IllegalArgumentException("Direct connections are not supported when using mongodb+srv protocol"); } if (this.hosts.size() > 1) { throw new IllegalArgumentException("Direct connections are not supported when using multiple hosts"); } } if (this.loadBalanced != null && this.loadBalanced.booleanValue()) { if (this.directConnection != null && this.directConnection.booleanValue()) { throw new IllegalArgumentException("directConnection=true can not be specified with loadBalanced=true"); } if (this.requiredReplicaSetName != null) { throw new IllegalArgumentException("replicaSet can not be specified with loadBalanced=true"); } if (this.hosts.size() > 1) { throw new IllegalArgumentException("Only one host can be specified with loadBalanced=true"); } if (this.srvMaxHosts != null && this.srvMaxHosts > 0) { throw new IllegalArgumentException("srvMaxHosts can not be specified with loadBalanced=true"); } } if (this.requiredReplicaSetName != null && this.srvMaxHosts != null && this.srvMaxHosts > 0) { throw new IllegalArgumentException("srvMaxHosts can not be specified with replica set name"); } this.credential = this.createCredentials(combinedOptionsMaps, userName, password); this.warnOnUnsupportedOptions(combinedOptionsMaps); } private Map> combineOptionsMaps(Map> txtRecordsOptionsMap, Map> connectionStringOptionsMap) { HashMap combinedOptionsMaps = new HashMap(txtRecordsOptionsMap); for (Map.Entry entry : connectionStringOptionsMap.entrySet()) { combinedOptionsMaps.put((Object)((String)entry.getKey()), (Object)((List)entry.getValue())); } return combinedOptionsMaps; } private void warnOnUnsupportedOptions(Map> optionsMap) { for (String key : optionsMap.keySet()) { if (ALL_KEYS.contains((Object)key) || !LOGGER.isWarnEnabled()) continue; LOGGER.warn(String.format((String)"Connection string contains unsupported option '%s'.", (Object[])new Object[]{key})); } } private void translateOptions(Map> optionsMap) { boolean tlsInsecureSet = false; boolean tlsAllowInvalidHostnamesSet = false; for (String key : GENERAL_OPTIONS_KEYS) { String value = this.getLastValue(optionsMap, key); if (value == null) continue; if (key.equals((Object)"maxpoolsize")) { this.maxConnectionPoolSize = this.parseInteger(value, "maxpoolsize"); continue; } if (key.equals((Object)"minpoolsize")) { this.minConnectionPoolSize = this.parseInteger(value, "minpoolsize"); continue; } if (key.equals((Object)"maxidletimems")) { this.maxConnectionIdleTime = this.parseInteger(value, "maxidletimems"); continue; } if (key.equals((Object)"maxlifetimems")) { this.maxConnectionLifeTime = this.parseInteger(value, "maxlifetimems"); continue; } if (key.equals((Object)"maxconnecting")) { this.maxConnecting = this.parseInteger(value, "maxConnecting"); continue; } if (key.equals((Object)"waitqueuetimeoutms")) { this.maxWaitTime = this.parseInteger(value, "waitqueuetimeoutms"); continue; } if (key.equals((Object)"connecttimeoutms")) { this.connectTimeout = this.parseInteger(value, "connecttimeoutms"); continue; } if (key.equals((Object)"sockettimeoutms")) { this.socketTimeout = this.parseInteger(value, "sockettimeoutms"); continue; } if (key.equals((Object)"tlsallowinvalidhostnames")) { this.sslInvalidHostnameAllowed = this.parseBoolean(value, "tlsAllowInvalidHostnames"); tlsAllowInvalidHostnamesSet = true; continue; } if (key.equals((Object)"sslinvalidhostnameallowed")) { this.sslInvalidHostnameAllowed = this.parseBoolean(value, "sslinvalidhostnameallowed"); tlsAllowInvalidHostnamesSet = true; continue; } if (key.equals((Object)"tlsinsecure")) { this.sslInvalidHostnameAllowed = this.parseBoolean(value, "tlsinsecure"); tlsInsecureSet = true; continue; } if (key.equals((Object)"ssl")) { this.initializeSslEnabled("ssl", value); continue; } if (key.equals((Object)"tls")) { this.initializeSslEnabled("tls", value); continue; } if (key.equals((Object)"replicaset")) { this.requiredReplicaSetName = value; continue; } if (key.equals((Object)"readconcernlevel")) { this.readConcern = new ReadConcern(ReadConcernLevel.fromString((String)value)); continue; } if (key.equals((Object)"serverselectiontimeoutms")) { this.serverSelectionTimeout = this.parseInteger(value, "serverselectiontimeoutms"); continue; } if (key.equals((Object)"localthresholdms")) { this.localThreshold = this.parseInteger(value, "localthresholdms"); continue; } if (key.equals((Object)"heartbeatfrequencyms")) { this.heartbeatFrequency = this.parseInteger(value, "heartbeatfrequencyms"); continue; } if (key.equals((Object)"appname")) { this.applicationName = value; continue; } if (key.equals((Object)"retrywrites")) { this.retryWrites = this.parseBoolean(value, "retrywrites"); continue; } if (key.equals((Object)"retryreads")) { this.retryReads = this.parseBoolean(value, "retryreads"); continue; } if (key.equals((Object)"uuidrepresentation")) { this.uuidRepresentation = this.createUuidRepresentation(value); continue; } if (key.equals((Object)"directconnection")) { this.directConnection = this.parseBoolean(value, "directconnection"); continue; } if (key.equals((Object)"loadbalanced")) { this.loadBalanced = this.parseBoolean(value, "loadbalanced"); continue; } if (key.equals((Object)"srvmaxhosts")) { this.srvMaxHosts = this.parseInteger(value, "srvmaxhosts"); if (this.srvMaxHosts >= 0) continue; throw new IllegalArgumentException("srvMaxHosts must be >= 0"); } if (!key.equals((Object)"srvservicename")) continue; this.srvServiceName = value; } if (tlsInsecureSet && tlsAllowInvalidHostnamesSet) { throw new IllegalArgumentException("tlsAllowInvalidHostnames or sslInvalidHostnameAllowed set along with tlsInsecure is not allowed"); } this.writeConcern = this.createWriteConcern(optionsMap); this.readPreference = this.createReadPreference(optionsMap); this.compressorList = this.createCompressors(optionsMap); } private void initializeSslEnabled(String key, String value) { Boolean booleanValue = this.parseBoolean(value, key); if (this.sslEnabled != null && !this.sslEnabled.equals((Object)booleanValue)) { throw new IllegalArgumentException("Conflicting tls and ssl parameter values are not allowed"); } this.sslEnabled = booleanValue; } private List createCompressors(Map> optionsMap) { String compressors = ""; Integer zlibCompressionLevel = null; for (String key : COMPRESSOR_KEYS) { String value = this.getLastValue(optionsMap, key); if (value == null) continue; if (key.equals((Object)"compressors")) { compressors = value; continue; } if (!key.equals((Object)"zlibcompressionlevel")) continue; zlibCompressionLevel = Integer.parseInt((String)value); } return this.buildCompressors(compressors, zlibCompressionLevel); } private List buildCompressors(String compressors, @Nullable Integer zlibCompressionLevel) { ArrayList compressorsList = new ArrayList(); for (String cur : compressors.split(",")) { if (cur.equals((Object)"zlib")) { MongoCompressor zlibCompressor = MongoCompressor.createZlibCompressor(); if (zlibCompressionLevel != null) { zlibCompressor = zlibCompressor.withProperty("LEVEL", (Object)zlibCompressionLevel); } compressorsList.add((Object)zlibCompressor); continue; } if (cur.equals((Object)"snappy")) { compressorsList.add((Object)MongoCompressor.createSnappyCompressor()); continue; } if (cur.equals((Object)"zstd")) { compressorsList.add((Object)MongoCompressor.createZstdCompressor()); continue; } if (cur.isEmpty()) continue; throw new IllegalArgumentException("Unsupported compressor '" + cur + "'"); } return Collections.unmodifiableList((List)compressorsList); } @Nullable private WriteConcern createWriteConcern(Map> optionsMap) { String w = null; Integer wTimeout = null; Boolean safe = null; Boolean journal = null; for (String key : WRITE_CONCERN_KEYS) { String value = this.getLastValue(optionsMap, key); if (value == null) continue; if (key.equals((Object)"safe")) { safe = this.parseBoolean(value, "safe"); continue; } if (key.equals((Object)"w")) { w = value; continue; } if (key.equals((Object)"wtimeoutms")) { wTimeout = Integer.parseInt((String)value); continue; } if (!key.equals((Object)"journal")) continue; journal = this.parseBoolean(value, "journal"); } return this.buildWriteConcern(safe, w, wTimeout, journal); } @Nullable private ReadPreference createReadPreference(Map> optionsMap) { String readPreferenceType = null; ArrayList tagSetList = new ArrayList(); long maxStalenessSeconds = -1L; for (String key : READ_PREFERENCE_KEYS) { String value = this.getLastValue(optionsMap, key); if (value == null) continue; if (key.equals((Object)"readpreference")) { readPreferenceType = value; continue; } if (key.equals((Object)"maxstalenessseconds")) { maxStalenessSeconds = this.parseInteger(value, "maxstalenessseconds"); continue; } if (!key.equals((Object)"readpreferencetags")) continue; for (String cur : (List)optionsMap.get((Object)key)) { TagSet tagSet = this.getTags(cur.trim()); tagSetList.add((Object)tagSet); } } return this.buildReadPreference(readPreferenceType, (List)tagSetList, maxStalenessSeconds); } private UuidRepresentation createUuidRepresentation(String value) { if (value.equalsIgnoreCase("unspecified")) { return UuidRepresentation.UNSPECIFIED; } if (value.equalsIgnoreCase("javaLegacy")) { return UuidRepresentation.JAVA_LEGACY; } if (value.equalsIgnoreCase("csharpLegacy")) { return UuidRepresentation.C_SHARP_LEGACY; } if (value.equalsIgnoreCase("pythonLegacy")) { return UuidRepresentation.PYTHON_LEGACY; } if (value.equalsIgnoreCase("standard")) { return UuidRepresentation.STANDARD; } throw new IllegalArgumentException("Unknown uuid representation: " + value); } @Nullable private MongoCredential createCredentials(Map> optionsMap, @Nullable String userName, @Nullable char[] password) { AuthenticationMechanism mechanism = null; String authSource = null; String gssapiServiceName = null; String authMechanismProperties = null; for (String key : AUTH_KEYS) { String value = this.getLastValue(optionsMap, key); if (value == null) continue; if (key.equals((Object)"authmechanism")) { if (value.equals((Object)"MONGODB-CR")) { if (userName == null) { throw new IllegalArgumentException("username can not be null"); } LOGGER.warn("Deprecated MONGDOB-CR authentication mechanism used in connection string"); continue; } mechanism = AuthenticationMechanism.fromMechanismName((String)value); continue; } if (key.equals((Object)"authsource")) { if (value.equals((Object)"")) { throw new IllegalArgumentException("authSource can not be an empty string"); } authSource = value; continue; } if (key.equals((Object)"gssapiservicename")) { gssapiServiceName = value; continue; } if (!key.equals((Object)"authmechanismproperties")) continue; authMechanismProperties = value; } MongoCredential credential = null; if (mechanism != null) { credential = this.createMongoCredentialWithMechanism(mechanism, userName, password, authSource, gssapiServiceName); } else if (userName != null) { credential = MongoCredential.createCredential((String)userName, (String)this.getAuthSourceOrDefault(authSource, this.database != null ? this.database : "admin"), (char[])password); } if (credential != null && authMechanismProperties != null) { for (String part : authMechanismProperties.split(",")) { String[] mechanismPropertyKeyValue = part.split(":"); if (mechanismPropertyKeyValue.length != 2) { throw new IllegalArgumentException(String.format((String)"The connection string contains invalid authentication properties. '%s' is not a key value pair", (Object[])new Object[]{part})); } String key = mechanismPropertyKeyValue[0].trim().toLowerCase(); String value = mechanismPropertyKeyValue[1].trim(); credential = key.equals((Object)"canonicalize_host_name") ? credential.withMechanismProperty(key, (Object)Boolean.valueOf((String)value)) : credential.withMechanismProperty(key, (Object)value); } } return credential; } private MongoCredential createMongoCredentialWithMechanism(AuthenticationMechanism mechanism, String userName, @Nullable char[] password, @Nullable String authSource, @Nullable String gssapiServiceName) { MongoCredential credential; String mechanismAuthSource; switch (1.$SwitchMap$com$mongodb$AuthenticationMechanism[mechanism.ordinal()]) { case 1: { mechanismAuthSource = this.getAuthSourceOrDefault(authSource, this.database != null ? this.database : "$external"); break; } case 2: case 3: { mechanismAuthSource = this.getAuthSourceOrDefault(authSource, "$external"); if (mechanismAuthSource.equals((Object)"$external")) break; throw new IllegalArgumentException(String.format((String)"Invalid authSource for %s, it must be '$external'", (Object[])new Object[]{mechanism})); } default: { mechanismAuthSource = this.getAuthSourceOrDefault(authSource, this.database != null ? this.database : "admin"); } } switch (1.$SwitchMap$com$mongodb$AuthenticationMechanism[mechanism.ordinal()]) { case 2: { credential = MongoCredential.createGSSAPICredential((String)userName); if (gssapiServiceName != null) { credential = credential.withMechanismProperty("SERVICE_NAME", (Object)gssapiServiceName); } if (password == null || !LOGGER.isWarnEnabled()) break; LOGGER.warn("Password in connection string not used with MONGODB_X509 authentication mechanism."); break; } case 1: { credential = MongoCredential.createPlainCredential((String)userName, (String)mechanismAuthSource, (char[])password); break; } case 3: { if (password != null) { throw new IllegalArgumentException("Invalid mechanism, MONGODB_x509 does not support passwords"); } credential = MongoCredential.createMongoX509Credential((String)userName); break; } case 4: { credential = MongoCredential.createScramSha1Credential((String)userName, (String)mechanismAuthSource, (char[])password); break; } case 5: { credential = MongoCredential.createScramSha256Credential((String)userName, (String)mechanismAuthSource, (char[])password); break; } case 6: { credential = MongoCredential.createAwsCredential((String)userName, (char[])password); break; } default: { throw new UnsupportedOperationException(String.format((String)"The connection string contains an invalid authentication mechanism'. '%s' is not a supported authentication mechanism", (Object[])new Object[]{mechanism})); } } return credential; } private String getAuthSourceOrDefault(@Nullable String authSource, String defaultAuthSource) { if (authSource != null) { return authSource; } return defaultAuthSource; } @Nullable private String getLastValue(Map> optionsMap, String key) { List valueList = (List)optionsMap.get((Object)key); if (valueList == null) { return null; } return (String)valueList.get(valueList.size() - 1); } private Map> parseOptions(String optionsPart) { String legacySecondaryOkOption; String legacySecondaryOk; HashMap optionsMap = new HashMap(); if (optionsPart.length() == 0) { return optionsMap; } for (String part : optionsPart.split("&|;")) { if (part.length() == 0) continue; int idx = part.indexOf("="); if (idx >= 0) { String key = part.substring(0, idx).toLowerCase(); String value = part.substring(idx + 1); List valueList = (List)optionsMap.get((Object)key); if (valueList == null) { valueList = new ArrayList(1); } valueList.add((Object)this.urldecode(value)); optionsMap.put((Object)key, (Object)valueList); continue; } throw new IllegalArgumentException(String.format((String)"The connection string contains an invalid option '%s'. '%s' is missing the value delimiter eg '%s=value'", (Object[])new Object[]{optionsPart, part, part})); } if (optionsMap.containsKey((Object)"wtimeout") && !optionsMap.containsKey((Object)"wtimeoutms")) { optionsMap.put((Object)"wtimeoutms", (Object)((List)optionsMap.remove((Object)"wtimeout"))); if (LOGGER.isWarnEnabled()) { LOGGER.warn("Uri option 'wtimeout' has been deprecated, use 'wtimeoutms' instead."); } } if ((legacySecondaryOk = this.getLastValue((Map>)optionsMap, legacySecondaryOkOption = "slaveok")) != null && !optionsMap.containsKey((Object)"readpreference")) { String readPreference = Boolean.TRUE.equals((Object)this.parseBoolean(legacySecondaryOk, legacySecondaryOkOption)) ? "secondaryPreferred" : "primary"; optionsMap.put((Object)"readpreference", (Object)Collections.singletonList((Object)readPreference)); if (LOGGER.isWarnEnabled()) { LOGGER.warn(String.format((String)"Uri option '%s' has been deprecated, use 'readpreference' instead.", (Object[])new Object[]{legacySecondaryOkOption})); } } if (optionsMap.containsKey((Object)"j") && !optionsMap.containsKey((Object)"journal")) { optionsMap.put((Object)"journal", (Object)((List)optionsMap.remove((Object)"j"))); if (LOGGER.isWarnEnabled()) { LOGGER.warn("Uri option 'j' has been deprecated, use 'journal' instead."); } } return optionsMap; } @Nullable private ReadPreference buildReadPreference(@Nullable String readPreferenceType, List tagSetList, long maxStalenessSeconds) { if (readPreferenceType != null) { if (tagSetList.isEmpty() && maxStalenessSeconds == -1L) { return ReadPreference.valueOf((String)readPreferenceType); } if (maxStalenessSeconds == -1L) { return ReadPreference.valueOf((String)readPreferenceType, tagSetList); } return ReadPreference.valueOf((String)readPreferenceType, tagSetList, (long)maxStalenessSeconds, (TimeUnit)TimeUnit.SECONDS); } if (!tagSetList.isEmpty() || maxStalenessSeconds != -1L) { throw new IllegalArgumentException("Read preference mode must be specified if either read preference tags or max staleness is specified"); } return null; } @Nullable private WriteConcern buildWriteConcern(@Nullable Boolean safe, @Nullable String w, @Nullable Integer wTimeout, @Nullable Boolean journal) { WriteConcern retVal = null; if (w != null || wTimeout != null || journal != null) { if (w == null) { retVal = WriteConcern.ACKNOWLEDGED; } else { try { retVal = new WriteConcern(Integer.parseInt((String)w)); } catch (NumberFormatException e) { retVal = new WriteConcern(w); } } if (wTimeout != null) { retVal = retVal.withWTimeout((long)wTimeout.intValue(), TimeUnit.MILLISECONDS); } if (journal != null) { retVal = retVal.withJournal(journal); } return retVal; } if (safe != null) { retVal = safe != false ? WriteConcern.ACKNOWLEDGED : WriteConcern.UNACKNOWLEDGED; } return retVal; } private TagSet getTags(String tagSetString) { ArrayList tagList = new ArrayList(); if (tagSetString.length() > 0) { for (String tag : tagSetString.split(",")) { String[] tagKeyValuePair = tag.split(":"); if (tagKeyValuePair.length != 2) { throw new IllegalArgumentException(String.format((String)"The connection string contains an invalid read preference tag. '%s' is not a key value pair", (Object[])new Object[]{tagSetString})); } tagList.add((Object)new Tag(tagKeyValuePair[0].trim(), tagKeyValuePair[1].trim())); } } return new TagSet((List)tagList); } @Nullable private Boolean parseBoolean(String input, String key) { String trimmedInput = input.trim().toLowerCase(); if (TRUE_VALUES.contains((Object)trimmedInput)) { if (!trimmedInput.equals((Object)"true")) { LOGGER.warn(String.format((String)"Deprecated boolean value '%s' in the connection string for '%s'. Replace with 'true'", (Object[])new Object[]{trimmedInput, key})); } return true; } if (FALSE_VALUES.contains((Object)trimmedInput)) { if (!trimmedInput.equals((Object)"false")) { LOGGER.warn(String.format((String)"Deprecated boolean value '%s' in the connection string for '%s'. Replace with'false'", (Object[])new Object[]{trimmedInput, key})); } return false; } LOGGER.warn(String.format((String)"Ignoring unrecognized boolean value '%s' in the connection string for '%s'. Replace with either 'true' or 'false'", (Object[])new Object[]{trimmedInput, key})); return null; } private int parseInteger(String input, String key) { try { return Integer.parseInt((String)input); } catch (NumberFormatException e) { throw new IllegalArgumentException(String.format((String)"The connection string contains an invalid value for '%s'. '%s' is not a valid integer", (Object[])new Object[]{key, input})); } } private List parseHosts(List rawHosts) { if (rawHosts.size() == 0) { throw new IllegalArgumentException("The connection string must contain at least one host"); } ArrayList hosts = new ArrayList(); for (String host : rawHosts) { if (host.length() == 0) { throw new IllegalArgumentException(String.format((String)"The connection string contains an empty host '%s'. ", (Object[])new Object[]{rawHosts})); } if (host.endsWith(".sock")) { host = this.urldecode(host); } else if (host.startsWith("[")) { if (!host.contains((CharSequence)"]")) { throw new IllegalArgumentException(String.format((String)"The connection string contains an invalid host '%s'. IPv6 address literals must be enclosed in '[' and ']' according to RFC 2732", (Object[])new Object[]{host})); } int idx = host.indexOf("]:"); if (idx != -1) { this.validatePort(host, host.substring(idx + 2)); } } else { int colonCount = this.countOccurrences(host, ":"); if (colonCount > 1) { throw new IllegalArgumentException(String.format((String)"The connection string contains an invalid host '%s'. Reserved characters such as ':' must be escaped according RFC 2396. Any IPv6 address literal must be enclosed in '[' and ']' according to RFC 2732.", (Object[])new Object[]{host})); } if (colonCount == 1) { this.validatePort(host, host.substring(host.indexOf(":") + 1)); } } hosts.add((Object)host); } Collections.sort((List)hosts); return hosts; } private void validatePort(String host, String port) { boolean invalidPort = false; try { int portInt = Integer.parseInt((String)port); if (portInt <= 0 || portInt > 65535) { invalidPort = true; } } catch (NumberFormatException e) { invalidPort = true; } if (invalidPort) { throw new IllegalArgumentException(String.format((String)"The connection string contains an invalid host '%s'. The port '%s' is not a valid, it must be an integer between 0 and 65535", (Object[])new Object[]{host, port})); } } private int countOccurrences(String haystack, String needle) { return haystack.length() - haystack.replace((CharSequence)needle, (CharSequence)"").length(); } private String urldecode(String input) { return this.urldecode(input, false); } private String urldecode(String input, boolean password) { try { return URLDecoder.decode((String)input, (String)StandardCharsets.UTF_8.name()); } catch (UnsupportedEncodingException e) { if (password) { throw new IllegalArgumentException("The connection string contained unsupported characters in the password."); } throw new IllegalArgumentException(String.format((String)"The connection string contained unsupported characters: '%s'.Decoding produced the following error: %s", (Object[])new Object[]{input, e.getMessage()})); } } @Nullable public String getUsername() { return this.credential != null ? this.credential.getUserName() : null; } @Nullable public char[] getPassword() { return this.credential != null ? this.credential.getPassword() : null; } public boolean isSrvProtocol() { return this.isSrvProtocol; } @Nullable public Integer getSrvMaxHosts() { return this.srvMaxHosts; } @Nullable public String getSrvServiceName() { return this.srvServiceName; } public List getHosts() { return this.hosts; } @Nullable public String getDatabase() { return this.database; } @Nullable public String getCollection() { return this.collection; } @Nullable public Boolean isDirectConnection() { return this.directConnection; } @Nullable public Boolean isLoadBalanced() { return this.loadBalanced; } public String getConnectionString() { return this.connectionString; } @Nullable public MongoCredential getCredential() { return this.credential; } @Nullable public ReadPreference getReadPreference() { return this.readPreference; } @Nullable public ReadConcern getReadConcern() { return this.readConcern; } @Nullable public WriteConcern getWriteConcern() { return this.writeConcern; } @Nullable public Boolean getRetryWritesValue() { return this.retryWrites; } @Nullable public Boolean getRetryReads() { return this.retryReads; } @Nullable public Integer getMinConnectionPoolSize() { return this.minConnectionPoolSize; } @Nullable public Integer getMaxConnectionPoolSize() { return this.maxConnectionPoolSize; } @Nullable public Integer getMaxWaitTime() { return this.maxWaitTime; } @Nullable public Integer getMaxConnectionIdleTime() { return this.maxConnectionIdleTime; } @Nullable public Integer getMaxConnectionLifeTime() { return this.maxConnectionLifeTime; } @Nullable public Integer getMaxConnecting() { return this.maxConnecting; } @Nullable public Integer getConnectTimeout() { return this.connectTimeout; } @Nullable public Integer getSocketTimeout() { return this.socketTimeout; } @Nullable public Boolean getSslEnabled() { return this.sslEnabled; } @Nullable public Boolean getSslInvalidHostnameAllowed() { return this.sslInvalidHostnameAllowed; } @Nullable public String getRequiredReplicaSetName() { return this.requiredReplicaSetName; } @Nullable public Integer getServerSelectionTimeout() { return this.serverSelectionTimeout; } @Nullable public Integer getLocalThreshold() { return this.localThreshold; } @Nullable public Integer getHeartbeatFrequency() { return this.heartbeatFrequency; } @Nullable public String getApplicationName() { return this.applicationName; } public List getCompressorList() { return this.compressorList; } @Nullable public UuidRepresentation getUuidRepresentation() { return this.uuidRepresentation; } public String toString() { return this.connectionString; } public boolean equals(Object o) { if (this == o) { return true; } if (o == null || this.getClass() != o.getClass()) { return false; } ConnectionString that = (ConnectionString)o; return this.isSrvProtocol == that.isSrvProtocol && Objects.equals((Object)this.directConnection, (Object)that.directConnection) && Objects.equals((Object)this.credential, (Object)that.credential) && Objects.equals(this.hosts, that.hosts) && Objects.equals((Object)this.database, (Object)that.database) && Objects.equals((Object)this.collection, (Object)that.collection) && Objects.equals((Object)this.readPreference, (Object)that.readPreference) && Objects.equals((Object)this.writeConcern, (Object)that.writeConcern) && Objects.equals((Object)this.retryWrites, (Object)that.retryWrites) && Objects.equals((Object)this.retryReads, (Object)that.retryReads) && Objects.equals((Object)this.readConcern, (Object)that.readConcern) && Objects.equals((Object)this.minConnectionPoolSize, (Object)that.minConnectionPoolSize) && Objects.equals((Object)this.maxConnectionPoolSize, (Object)that.maxConnectionPoolSize) && Objects.equals((Object)this.maxWaitTime, (Object)that.maxWaitTime) && Objects.equals((Object)this.maxConnectionIdleTime, (Object)that.maxConnectionIdleTime) && Objects.equals((Object)this.maxConnectionLifeTime, (Object)that.maxConnectionLifeTime) && Objects.equals((Object)this.maxConnecting, (Object)that.maxConnecting) && Objects.equals((Object)this.connectTimeout, (Object)that.connectTimeout) && Objects.equals((Object)this.socketTimeout, (Object)that.socketTimeout) && Objects.equals((Object)this.sslEnabled, (Object)that.sslEnabled) && Objects.equals((Object)this.sslInvalidHostnameAllowed, (Object)that.sslInvalidHostnameAllowed) && Objects.equals((Object)this.requiredReplicaSetName, (Object)that.requiredReplicaSetName) && Objects.equals((Object)this.serverSelectionTimeout, (Object)that.serverSelectionTimeout) && Objects.equals((Object)this.localThreshold, (Object)that.localThreshold) && Objects.equals((Object)this.heartbeatFrequency, (Object)that.heartbeatFrequency) && Objects.equals((Object)this.applicationName, (Object)that.applicationName) && Objects.equals(this.compressorList, that.compressorList) && Objects.equals((Object)this.uuidRepresentation, (Object)that.uuidRepresentation) && Objects.equals((Object)this.srvServiceName, (Object)that.srvServiceName) && Objects.equals((Object)this.srvMaxHosts, (Object)that.srvMaxHosts); } public int hashCode() { return Objects.hash((Object[])new Object[]{this.credential, this.isSrvProtocol, this.hosts, this.database, this.collection, this.directConnection, this.readPreference, this.writeConcern, this.retryWrites, this.retryReads, this.readConcern, this.minConnectionPoolSize, this.maxConnectionPoolSize, this.maxWaitTime, this.maxConnectionIdleTime, this.maxConnectionLifeTime, this.maxConnecting, this.connectTimeout, this.socketTimeout, this.sslEnabled, this.sslInvalidHostnameAllowed, this.requiredReplicaSetName, this.serverSelectionTimeout, this.localThreshold, this.heartbeatFrequency, this.applicationName, this.compressorList, this.uuidRepresentation, this.srvServiceName, this.srvMaxHosts}); } static { GENERAL_OPTIONS_KEYS.add((Object)"minpoolsize"); GENERAL_OPTIONS_KEYS.add((Object)"maxpoolsize"); GENERAL_OPTIONS_KEYS.add((Object)"waitqueuetimeoutms"); GENERAL_OPTIONS_KEYS.add((Object)"connecttimeoutms"); GENERAL_OPTIONS_KEYS.add((Object)"maxidletimems"); GENERAL_OPTIONS_KEYS.add((Object)"maxlifetimems"); GENERAL_OPTIONS_KEYS.add((Object)"maxconnecting"); GENERAL_OPTIONS_KEYS.add((Object)"sockettimeoutms"); GENERAL_OPTIONS_KEYS.add((Object)"ssl"); GENERAL_OPTIONS_KEYS.add((Object)"tls"); GENERAL_OPTIONS_KEYS.add((Object)"tlsinsecure"); GENERAL_OPTIONS_KEYS.add((Object)"sslinvalidhostnameallowed"); GENERAL_OPTIONS_KEYS.add((Object)"tlsallowinvalidhostnames"); GENERAL_OPTIONS_KEYS.add((Object)"replicaset"); GENERAL_OPTIONS_KEYS.add((Object)"readconcernlevel"); GENERAL_OPTIONS_KEYS.add((Object)"serverselectiontimeoutms"); GENERAL_OPTIONS_KEYS.add((Object)"localthresholdms"); GENERAL_OPTIONS_KEYS.add((Object)"heartbeatfrequencyms"); GENERAL_OPTIONS_KEYS.add((Object)"retrywrites"); GENERAL_OPTIONS_KEYS.add((Object)"retryreads"); GENERAL_OPTIONS_KEYS.add((Object)"appname"); GENERAL_OPTIONS_KEYS.add((Object)"uuidrepresentation"); GENERAL_OPTIONS_KEYS.add((Object)"directconnection"); GENERAL_OPTIONS_KEYS.add((Object)"loadbalanced"); GENERAL_OPTIONS_KEYS.add((Object)"srvmaxhosts"); GENERAL_OPTIONS_KEYS.add((Object)"srvservicename"); COMPRESSOR_KEYS.add((Object)"compressors"); COMPRESSOR_KEYS.add((Object)"zlibcompressionlevel"); READ_PREFERENCE_KEYS.add((Object)"readpreference"); READ_PREFERENCE_KEYS.add((Object)"readpreferencetags"); READ_PREFERENCE_KEYS.add((Object)"maxstalenessseconds"); WRITE_CONCERN_KEYS.add((Object)"safe"); WRITE_CONCERN_KEYS.add((Object)"w"); WRITE_CONCERN_KEYS.add((Object)"wtimeoutms"); WRITE_CONCERN_KEYS.add((Object)"journal"); AUTH_KEYS.add((Object)"authmechanism"); AUTH_KEYS.add((Object)"authsource"); AUTH_KEYS.add((Object)"gssapiservicename"); AUTH_KEYS.add((Object)"authmechanismproperties"); ALL_KEYS.addAll(GENERAL_OPTIONS_KEYS); ALL_KEYS.addAll(AUTH_KEYS); ALL_KEYS.addAll(READ_PREFERENCE_KEYS); ALL_KEYS.addAll(WRITE_CONCERN_KEYS); ALL_KEYS.addAll(COMPRESSOR_KEYS); TRUE_VALUES = new HashSet((Collection)Arrays.asList((Object[])new String[]{"true", "yes", "1"})); FALSE_VALUES = new HashSet((Collection)Arrays.asList((Object[])new String[]{"false", "no", "0"})); } }