001/*
002 * Copyright 2012-2017 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.net.UnknownHostException;
020import java.util.ArrayList;
021import java.util.Collections;
022import java.util.List;
023
024import com.mongodb.MongoClient;
025import com.mongodb.MongoClientOptions;
026import com.mongodb.MongoClientOptions.Builder;
027import com.mongodb.MongoClientURI;
028import com.mongodb.MongoCredential;
029import com.mongodb.ServerAddress;
030
031import org.springframework.boot.context.properties.ConfigurationProperties;
032import org.springframework.core.env.Environment;
033
034/**
035 * Configuration properties for Mongo.
036 *
037 * @author Dave Syer
038 * @author Phillip Webb
039 * @author Josh Long
040 * @author Andy Wilkinson
041 * @author Eddú Meléndez
042 * @author Stephane Nicoll
043 * @author Nasko Vasilev
044 */
045@ConfigurationProperties(prefix = "spring.data.mongodb")
046public class MongoProperties {
047
048        /**
049         * Default port used when the configured port is {@code null}.
050         */
051        public static final int DEFAULT_PORT = 27017;
052
053        public static final String DEFAULT_URI = "mongodb://localhost/test";
054
055        /**
056         * Mongo server host. Cannot be set with uri.
057         */
058        private String host;
059
060        /**
061         * Mongo server port. Cannot be set with uri.
062         */
063        private Integer port = null;
064
065        /**
066         * Mongo database URI. Cannot be set with host, port and credentials.
067         */
068        private String uri;
069
070        /**
071         * Database name.
072         */
073        private String database;
074
075        /**
076         * Authentication database name.
077         */
078        private String authenticationDatabase;
079
080        /**
081         * GridFS database name.
082         */
083        private String gridFsDatabase;
084
085        /**
086         * Login user of the mongo server. Cannot be set with uri.
087         */
088        private String username;
089
090        /**
091         * Login password of the mongo server. Cannot be set with uri.
092         */
093        private char[] password;
094
095        /**
096         * Fully qualified name of the FieldNamingStrategy to use.
097         */
098        private Class<?> fieldNamingStrategy;
099
100        public String getHost() {
101                return this.host;
102        }
103
104        public void setHost(String host) {
105                this.host = host;
106        }
107
108        public String getDatabase() {
109                return this.database;
110        }
111
112        public void setDatabase(String database) {
113                this.database = database;
114        }
115
116        public String getAuthenticationDatabase() {
117                return this.authenticationDatabase;
118        }
119
120        public void setAuthenticationDatabase(String authenticationDatabase) {
121                this.authenticationDatabase = authenticationDatabase;
122        }
123
124        public String getUsername() {
125                return this.username;
126        }
127
128        public void setUsername(String username) {
129                this.username = username;
130        }
131
132        public char[] getPassword() {
133                return this.password;
134        }
135
136        public void setPassword(char[] password) {
137                this.password = password;
138        }
139
140        public Class<?> getFieldNamingStrategy() {
141                return this.fieldNamingStrategy;
142        }
143
144        public void setFieldNamingStrategy(Class<?> fieldNamingStrategy) {
145                this.fieldNamingStrategy = fieldNamingStrategy;
146        }
147
148        public void clearPassword() {
149                if (this.password == null) {
150                        return;
151                }
152                for (int i = 0; i < this.password.length; i++) {
153                        this.password[i] = 0;
154                }
155        }
156
157        public String getUri() {
158                return this.uri;
159        }
160
161        public String determineUri() {
162                return (this.uri != null ? this.uri : DEFAULT_URI);
163        }
164
165        public void setUri(String uri) {
166                this.uri = uri;
167        }
168
169        public Integer getPort() {
170                return this.port;
171        }
172
173        public void setPort(Integer port) {
174                this.port = port;
175        }
176
177        public String getGridFsDatabase() {
178                return this.gridFsDatabase;
179        }
180
181        public void setGridFsDatabase(String gridFsDatabase) {
182                this.gridFsDatabase = gridFsDatabase;
183        }
184
185        public String getMongoClientDatabase() {
186                if (this.database != null) {
187                        return this.database;
188                }
189                return new MongoClientURI(determineUri()).getDatabase();
190        }
191
192        /**
193         * Creates a {@link MongoClient} using the given {@code options} and
194         * {@code environment}. If the environment contains a {@code local.mongo.port}
195         * property, it is used to configure a client to an embedded MongoDB instance.
196         * @param options the options
197         * @param environment the environment
198         * @return the Mongo client
199         * @throws UnknownHostException if the configured host is unknown
200         */
201        public MongoClient createMongoClient(MongoClientOptions options,
202                        Environment environment) throws UnknownHostException {
203                try {
204                        Integer embeddedPort = getEmbeddedPort(environment);
205                        if (embeddedPort != null) {
206                                return createEmbeddedMongoClient(options, embeddedPort);
207                        }
208                        return createNetworkMongoClient(options);
209                }
210                finally {
211                        clearPassword();
212                }
213        }
214
215        private Integer getEmbeddedPort(Environment environment) {
216                if (environment != null) {
217                        String localPort = environment.getProperty("local.mongo.port");
218                        if (localPort != null) {
219                                return Integer.valueOf(localPort);
220                        }
221                }
222                return null;
223        }
224
225        private MongoClient createEmbeddedMongoClient(MongoClientOptions options, int port) {
226                if (options == null) {
227                        options = MongoClientOptions.builder().build();
228                }
229                String host = this.host == null ? "localhost" : this.host;
230                return new MongoClient(Collections.singletonList(new ServerAddress(host, port)),
231                                Collections.<MongoCredential>emptyList(), options);
232        }
233
234        private MongoClient createNetworkMongoClient(MongoClientOptions options) {
235                if (hasCustomAddress() || hasCustomCredentials()) {
236                        if (this.uri != null) {
237                                throw new IllegalStateException("Invalid mongo configuration, "
238                                                + "either uri or host/port/credentials must be specified");
239                        }
240                        if (options == null) {
241                                options = MongoClientOptions.builder().build();
242                        }
243                        List<MongoCredential> credentials = new ArrayList<MongoCredential>();
244                        if (hasCustomCredentials()) {
245                                String database = this.authenticationDatabase == null
246                                                ? getMongoClientDatabase() : this.authenticationDatabase;
247                                credentials.add(MongoCredential.createCredential(this.username, database,
248                                                this.password));
249                        }
250                        String host = this.host == null ? "localhost" : this.host;
251                        int port = this.port != null ? this.port : DEFAULT_PORT;
252                        return new MongoClient(
253                                        Collections.singletonList(new ServerAddress(host, port)), credentials,
254                                        options);
255                }
256                // The options and credentials are in the URI
257                return new MongoClient(new MongoClientURI(determineUri(), builder(options)));
258        }
259
260        private boolean hasCustomAddress() {
261                return this.host != null || this.port != null;
262        }
263
264        private boolean hasCustomCredentials() {
265                return this.username != null && this.password != null;
266        }
267
268        private Builder builder(MongoClientOptions options) {
269                if (options != null) {
270                        return MongoClientOptions.builder(options);
271                }
272                return MongoClientOptions.builder();
273        }
274
275}