package de.is24.infrastructure.gridfs.http.mongo;
import com.mongodb.FastestPingTimeReadPreference;
import com.mongodb.Mongo;
import com.mongodb.MongoClientOptions;
import com.mongodb.MongoCredential;
import com.mongodb.MongoException;
import com.mongodb.ServerAddress;
import com.mongodb.WriteConcern;
import com.mongodb.gridfs.GridFS;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.config.AbstractMongoConfiguration;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.gridfs.GridFsTemplate;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
import org.springframework.data.mongodb.tx.MongoTxProxy;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
import static com.mongodb.MongoCredential.createCredential;
import static com.mongodb.WriteConcern.ACKNOWLEDGED;
import static com.mongodb.WriteConcern.W2;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static java.util.regex.Pattern.compile;
@Configuration
@EnableMongoRepositories("de.is24.infrastructure.gridfs.http.metadata")
public class MongoConfig extends AbstractMongoConfiguration {
private static final Logger LOGGER = LoggerFactory.getLogger(MongoConfig.class);
private static final int CLUSTER_SIZE = 3;
private static final String SEPARATOR = ",";
private static final Pattern SEPARATOR_PATTERN = compile(SEPARATOR);
@Value("${mongodb.serverlist}")
String mongoDBServerList;
@Value("${mongodb.db.name:rpm_db}")
String mongoDBName;
@Value("${mongodb.db.user:@null}")
String mongoDBUsername;
@Value("${mongodb.db.pass:@null}")
String mongoDBPassword;
@Value("${mongodb.port:27017}")
String mongoDBPort;
@Value("${mongodb.socket.timeout:60}")
int mongoDBSocketTimeoutInSec;
@Bean
@Override
public Mongo mongo() throws UnknownHostException {
return new MongoTxProxy(getReplicatSet(), getCredentials(), mongoOptions());
}
@Bean
@Override
public MongoTemplate mongoTemplate() throws Exception {
int tries = 0;
while (tries < 3) {
try {
return new MongoTemplate(mongoDbFactory(), mappingMongoConverter());
} catch (MongoException e) {
if (e.getMessage().contains("can't find a master")) {
tries++;
LOGGER.warn("when creatig MongoTemplate: could not find a master, will retry in 10 seconds");
// switching mongo primary takes ~10 seconds
Thread.sleep(10000);
} else {
throw e;
}
}
}
throw new MongoException("could not find a master after three tries");
}
private MongoClientOptions mongoOptions() {
return new MongoClientOptions.Builder() //
.socketKeepAlive(true)
.readPreference(new FastestPingTimeReadPreference())
.writeConcern(getWriteConcern())
.connectionsPerHost(100)
.threadsAllowedToBlockForConnectionMultiplier(10)
.socketTimeout(mongoDBSocketTimeoutInSec * 1000)
.build();
}
@Bean
public GridFS gridFs() throws Exception {
return new GridFS(mongoDbFactory().getDb());
}
@Bean
public GridFsTemplate gridFsTemplate() throws Exception {
return new GridFsTemplate(mongoDbFactory(), mappingMongoConverter());
}
private WriteConcern getWriteConcern() {
if (mongoDBServerList.contains(SEPARATOR)) {
return W2;
}
return ACKNOWLEDGED;
}
private List<ServerAddress> getReplicatSet() throws UnknownHostException {
List<ServerAddress> hosts = new ArrayList<>(CLUSTER_SIZE);
for (String curServer : SEPARATOR_PATTERN.split(mongoDBServerList)) {
ServerAddress serverAddress;
serverAddress = new ServerAddress(curServer, Integer.parseInt(mongoDBPort));
hosts.add(serverAddress);
}
LOGGER.info("Start with " + hosts.toString());
return hosts;
}
@Override
protected String getDatabaseName() {
return mongoDBName;
}
protected List<MongoCredential> getCredentials() {
if (mongoDBUsername != null) {
return singletonList(createCredential(mongoDBUsername, mongoDBName, mongoDBPassword.toCharArray()));
}
return emptyList();
}
}