001/*
002 * Copyright 2012-2018 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.boot.autoconfigure.mongo;
018
019import java.util.Collections;
020import java.util.List;
021
022import com.mongodb.MongoClient;
023import com.mongodb.MongoClientOptions;
024import com.mongodb.MongoClientOptions.Builder;
025import com.mongodb.MongoClientURI;
026import com.mongodb.MongoCredential;
027import com.mongodb.ServerAddress;
028
029import org.springframework.core.env.Environment;
030
031/**
032 * A factory for a blocking {@link MongoClient} that applies {@link MongoProperties}.
033 *
034 * @author Dave Syer
035 * @author Phillip Webb
036 * @author Josh Long
037 * @author Andy Wilkinson
038 * @author EddĂș MelĂ©ndez
039 * @author Stephane Nicoll
040 * @author Nasko Vasilev
041 * @author Mark Paluch
042 * @since 2.0.0
043 */
044public class MongoClientFactory {
045
046        private final MongoProperties properties;
047
048        private final Environment environment;
049
050        public MongoClientFactory(MongoProperties properties, Environment environment) {
051                this.properties = properties;
052                this.environment = environment;
053        }
054
055        /**
056         * Creates a {@link MongoClient} using the given {@code options}. If the environment
057         * contains a {@code local.mongo.port} property, it is used to configure a client to
058         * an embedded MongoDB instance.
059         * @param options the options
060         * @return the Mongo client
061         */
062        public MongoClient createMongoClient(MongoClientOptions options) {
063                Integer embeddedPort = getEmbeddedPort();
064                if (embeddedPort != null) {
065                        return createEmbeddedMongoClient(options, embeddedPort);
066                }
067                return createNetworkMongoClient(options);
068        }
069
070        private Integer getEmbeddedPort() {
071                if (this.environment != null) {
072                        String localPort = this.environment.getProperty("local.mongo.port");
073                        if (localPort != null) {
074                                return Integer.valueOf(localPort);
075                        }
076                }
077                return null;
078        }
079
080        private MongoClient createEmbeddedMongoClient(MongoClientOptions options, int port) {
081                if (options == null) {
082                        options = MongoClientOptions.builder().build();
083                }
084                String host = (this.properties.getHost() != null) ? this.properties.getHost()
085                                : "localhost";
086                return new MongoClient(Collections.singletonList(new ServerAddress(host, port)),
087                                options);
088        }
089
090        private MongoClient createNetworkMongoClient(MongoClientOptions options) {
091                MongoProperties properties = this.properties;
092                if (properties.getUri() != null) {
093                        return createMongoClient(properties.getUri(), options);
094                }
095                if (hasCustomAddress() || hasCustomCredentials()) {
096                        if (options == null) {
097                                options = MongoClientOptions.builder().build();
098                        }
099                        MongoCredential credentials = getCredentials(properties);
100                        String host = getValue(properties.getHost(), "localhost");
101                        int port = getValue(properties.getPort(), MongoProperties.DEFAULT_PORT);
102                        List<ServerAddress> seeds = Collections
103                                        .singletonList(new ServerAddress(host, port));
104                        return (credentials != null) ? new MongoClient(seeds, credentials, options)
105                                        : new MongoClient(seeds, options);
106                }
107                return createMongoClient(MongoProperties.DEFAULT_URI, options);
108        }
109
110        private MongoClient createMongoClient(String uri, MongoClientOptions options) {
111                return new MongoClient(new MongoClientURI(uri, builder(options)));
112        }
113
114        private <T> T getValue(T value, T fallback) {
115                return (value != null) ? value : fallback;
116        }
117
118        private boolean hasCustomAddress() {
119                return this.properties.getHost() != null || this.properties.getPort() != null;
120        }
121
122        private MongoCredential getCredentials(MongoProperties properties) {
123                if (!hasCustomCredentials()) {
124                        return null;
125                }
126                String username = properties.getUsername();
127                String database = getValue(properties.getAuthenticationDatabase(),
128                                properties.getMongoClientDatabase());
129                char[] password = properties.getPassword();
130                return MongoCredential.createCredential(username, database, password);
131        }
132
133        private boolean hasCustomCredentials() {
134                return this.properties.getUsername() != null
135                                && this.properties.getPassword() != null;
136        }
137
138        private Builder builder(MongoClientOptions options) {
139                if (options != null) {
140                        return MongoClientOptions.builder(options);
141                }
142                return MongoClientOptions.builder();
143        }
144
145}