package com.mastfrog.acteur.mongo; import com.google.inject.Inject; import com.google.inject.Provider; import com.google.inject.Singleton; import com.google.inject.name.Named; import static com.mastfrog.acteur.mongo.GiuliusMongoModule.DATABASE_NAME; import static com.mastfrog.acteur.mongo.GiuliusMongoModule.DEFAULT_MAX_CONNECTIONS; import static com.mastfrog.acteur.mongo.GiuliusMongoModule.DEFAULT_MAX_WAIT_MILLIS; import static com.mastfrog.acteur.mongo.GiuliusMongoModule.SETTINGS_KEY_MAX_CONNECTIONS; import static com.mastfrog.acteur.mongo.GiuliusMongoModule.SETTINGS_KEY_MAX_WAIT_MILLIS; import static com.mastfrog.acteur.mongo.GiuliusMongoModule.SETTINGS_KEY_MONGO_PASSWORD; import static com.mastfrog.acteur.mongo.GiuliusMongoModule.SETTINGS_KEY_MONGO_SSL; import static com.mastfrog.acteur.mongo.GiuliusMongoModule.SETTINGS_KEY_MONGO_SSL_INVALID_HOSTNAMES_ALLOWED; import static com.mastfrog.acteur.mongo.GiuliusMongoModule.SETTINGS_KEY_MONGO_USER; import com.mastfrog.giulius.ShutdownHookRegistry; import com.mastfrog.settings.Settings; import com.mastfrog.util.Exceptions; import com.mongodb.MongoClient; import com.mongodb.MongoClientOptions; import com.mongodb.MongoCredential; import com.mongodb.ReadPreference; import com.mongodb.ServerAddress; import java.util.ArrayList; import java.util.List; /** * * @author Tim Boudreau */ @Singleton final class MongoClientProvider implements Provider<MongoClient>, Runnable { private volatile MongoClient client; private final String dbName; private final Settings settings; private final ShutdownHookRegistry hooks; private volatile boolean added; private final MongoInitializer.Registry registry; @Inject(optional = true) @Named(GiuliusMongoModule.MONGO_HOST) private String host; @Inject(optional = true) @Named(GiuliusMongoModule.MONGO_PORT) private int port; @Inject public MongoClientProvider(@Named(DATABASE_NAME) String dbName, Settings settings, ShutdownHookRegistry hooks, MongoInitializer.Registry registry) { this.dbName = dbName; this.settings = settings; this.hooks = hooks; this.registry = registry; } private String mongoHost() { return host == null ? "localhost" : host; } private Integer mongoPort() { return port == 0 ? 27017 : port; } private void clear() { MongoClient client; synchronized (this) { client = this.client; this.client = null; } client.close(); } @Override public MongoClient get() { if (client == null) { synchronized (this) { if (client == null) { try { String host = mongoHost(); int port = mongoPort(); registry.onBeforeCreateMongoClient(host, port); int maxWait = settings.getInt(SETTINGS_KEY_MAX_WAIT_MILLIS, DEFAULT_MAX_WAIT_MILLIS); int maxConnections = settings.getInt(SETTINGS_KEY_MAX_CONNECTIONS, DEFAULT_MAX_CONNECTIONS); boolean ssl = settings.getBoolean(SETTINGS_KEY_MONGO_SSL, false); boolean invalidAllowed = settings.getBoolean(SETTINGS_KEY_MONGO_SSL_INVALID_HOSTNAMES_ALLOWED, false); MongoClientOptions opts = MongoClientOptions.builder().legacyDefaults() .connectionsPerHost(maxConnections) .sslEnabled(ssl) .sslInvalidHostNameAllowed(invalidAllowed) .cursorFinalizerEnabled(true) .readPreference(ReadPreference.nearest()) .maxWaitTime(maxWait).build(); List<MongoCredential> credentials = new ArrayList<>(); String un = settings.getString(SETTINGS_KEY_MONGO_USER); String pw = settings.getString(SETTINGS_KEY_MONGO_PASSWORD); if (un != null && pw != null) { MongoCredential cred = MongoCredential.createMongoCRCredential(un, dbName, pw.toCharArray()); credentials.add(cred); } else if (un != null) { MongoCredential cred = MongoCredential.createGSSAPICredential(un); credentials.add(cred); } ServerAddress addr = new ServerAddress(host, port); client = credentials.isEmpty() ? new MongoClient(addr, opts) : new MongoClient(addr, credentials, opts); registry.onMongoClientCreated(client); if (!added) { hooks.add(this); added = true; } } catch (Exception ex) { Exceptions.chuck(ex); } } } } return client; } @Override public void run() { MongoClient client; synchronized (this) { client = this.client; this.client = null; } if (client != null) { client.close(); } } }