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;
}
}
}