package de.otto.edison.mongo.configuration; import static java.util.stream.Collectors.toList; import static org.slf4j.LoggerFactory.getLogger; import static com.mongodb.MongoClientOptions.builder; import java.util.List; import java.util.Objects; import java.util.stream.Stream; import javax.validation.Valid; import javax.validation.constraints.Min; import org.bson.codecs.configuration.CodecRegistry; import org.hibernate.validator.constraints.NotEmpty; import org.slf4j.Logger; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.validation.annotation.Validated; import com.mongodb.MongoClientOptions; import com.mongodb.ReadPreference; import com.mongodb.ServerAddress; /** * Properties used to configure MongoDB clients. * * @since 1.0.0 */ @ConfigurationProperties(prefix = "edison.mongo") @Validated public class MongoProperties { private static final Logger LOG = getLogger(MongoProperties.class); /** * The MongoDB servers. Comma-separated list of host:port pairs. */ @NotEmpty private String[] host = {"localhost"}; /** * The MongoDB database. */ @NotEmpty private String db; /** * database user name */ private String user = ""; /** * database user password * @deprecated use password instead */ @Deprecated private String passwd = ""; /** * database user password */ private String password = ""; /** * Represents preferred replica set members to which a query or command can be sent. */ @NotEmpty private String readPreference = "primaryPreferred"; /** * Maximum time that a thread will block waiting for a connection. */ @Min(10) private int maxWaitTime = 5000; /** * Connection timeout in milliseconds. Must be > 0 */ @Min(10) private int connectTimeout = 5000; /** * Socket timeout. */ @Min(10) private int socketTimeout = 2000; /** * Sets the server selection timeout in milliseconds, which defines how long the driver will wait for server selection to * succeed before throwing an exception. */ @Min(1) private int serverSelectionTimeout = 30000; /** * Connection pool properties. */ @Valid private Connectionpool connectionpool = new Connectionpool(); public List<ServerAddress> getServers() { return Stream.of(host) .filter(Objects::nonNull) .map(this::toServerAddress) .filter(Objects::nonNull) .collect(toList()); } public String[] getHost() { return host; } public void setHost(String[] host) { this.host = host; } public String getDb() { return db; } public void setDb(String db) { this.db = db; } public String getUser() { return user; } public void setUser(String user) { this.user = user; } /** * @deprecated use #getPassword(); */ @Deprecated public String getPasswd() { return passwd; } /** * @param passwd database user password * @deprecated use #setPassword(String); otherwise password will not be sanitized */ @Deprecated public void setPasswd(String passwd) { this.passwd = passwd; } public String getPassword() { return password != null && !password.isEmpty() ? password : passwd; } public void setPassword(String password) { this.password = password; } public String getReadPreference() { return readPreference; } public void setReadPreference(String readPreference) { this.readPreference = readPreference; } public int getMaxWaitTime() { return maxWaitTime; } public void setMaxWaitTime(int maxWaitTime) { this.maxWaitTime = maxWaitTime; } public int getConnectTimeout() { return connectTimeout; } public void setConnectTimeout(int connectTimeout) { this.connectTimeout = connectTimeout; } public int getSocketTimeout() { return socketTimeout; } public void setSocketTimeout(int socketTimeout) { this.socketTimeout = socketTimeout; } public int getServerSelectionTimeout() { return serverSelectionTimeout; } public void setServerSelectionTimeout(int serverSelectionTimeout) { this.serverSelectionTimeout = serverSelectionTimeout; } public Connectionpool getConnectionpool() { return connectionpool; } public void setConnectionpool(Connectionpool connectionpool) { this.connectionpool = connectionpool; } public MongoClientOptions toMongoClientOptions(final CodecRegistry codecRegistry) { return builder() .codecRegistry(codecRegistry) .readPreference(ReadPreference.valueOf(readPreference)) .connectTimeout(connectTimeout) .socketTimeout(socketTimeout) .serverSelectionTimeout(serverSelectionTimeout) .cursorFinalizerEnabled(true) .maxWaitTime(maxWaitTime) .maxConnectionLifeTime(connectionpool.getMaxLifeTime()) .threadsAllowedToBlockForConnectionMultiplier(connectionpool.getBlockedConnectionMultiplier()) .maxConnectionIdleTime(connectionpool.getMaxIdleTime()) .minConnectionsPerHost(connectionpool.getMinSize()) .connectionsPerHost(connectionpool.getMaxSize()) .build(); } private ServerAddress toServerAddress(String server) { try { if (server.contains(":")) { String[] hostNamePortPair = server.split(":"); return new ServerAddress(hostNamePortPair[0], Integer.parseInt(hostNamePortPair[1])); } else { return new ServerAddress(server); } } catch (final NumberFormatException e) { LOG.warn("Invalid portNumber: " + e.getMessage(), e); return null; } } public static class Connectionpool { /** * Maximum number of connections allowed per host. */ @Min(1) private int maxSize = 100; /** * The minimum number of connections per host. A value of <code>0</code> will create connections lazily. */ @Min(0) private int minSize = 2; /** * This multiplier, multiplied with the maxSize property, gives the maximum number of threads that may be waiting for a * connection to become available from the pool. */ @Min(1) private int blockedConnectionMultiplier = 2; /** * Maximum life time for a pooled connection. */ @Min(1) private int maxLifeTime = 100000; /** * Maximum idle time for a pooled connection. */ @Min(1) private int maxIdleTime = 10000; public int getMaxSize() { return maxSize; } public void setMaxSize(int maxSize) { this.maxSize = maxSize; } public int getMinSize() { return minSize; } public void setMinSize(int minSize) { this.minSize = minSize; } public int getBlockedConnectionMultiplier() { return blockedConnectionMultiplier; } public void setBlockedConnectionMultiplier(int blockedConnectionMultiplier) { this.blockedConnectionMultiplier = blockedConnectionMultiplier; } public int getMaxLifeTime() { return maxLifeTime; } public void setMaxLifeTime(int maxLifeTime) { this.maxLifeTime = maxLifeTime; } public int getMaxIdleTime() { return maxIdleTime; } public void setMaxIdleTime(int maxIdleTime) { this.maxIdleTime = maxIdleTime; } } }