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.data.mongo; 018 019import com.mongodb.ClientSessionOptions; 020import com.mongodb.DB; 021import com.mongodb.MongoClient; 022import com.mongodb.client.ClientSession; 023import com.mongodb.client.MongoDatabase; 024 025import org.springframework.beans.factory.ObjectProvider; 026import org.springframework.boot.autoconfigure.AutoConfigureAfter; 027import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 028import org.springframework.boot.autoconfigure.condition.AnyNestedCondition; 029import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; 030import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; 031import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 032import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration.AnyMongoClientAvailable; 033import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration; 034import org.springframework.boot.autoconfigure.mongo.MongoProperties; 035import org.springframework.boot.context.properties.EnableConfigurationProperties; 036import org.springframework.context.annotation.Bean; 037import org.springframework.context.annotation.Conditional; 038import org.springframework.context.annotation.Configuration; 039import org.springframework.context.annotation.Import; 040import org.springframework.dao.DataAccessException; 041import org.springframework.dao.support.PersistenceExceptionTranslator; 042import org.springframework.data.mongodb.MongoDbFactory; 043import org.springframework.data.mongodb.core.MongoDbFactorySupport; 044import org.springframework.data.mongodb.core.MongoTemplate; 045import org.springframework.data.mongodb.core.SimpleMongoClientDbFactory; 046import org.springframework.data.mongodb.core.SimpleMongoDbFactory; 047import org.springframework.data.mongodb.core.convert.DbRefResolver; 048import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver; 049import org.springframework.data.mongodb.core.convert.MappingMongoConverter; 050import org.springframework.data.mongodb.core.convert.MongoConverter; 051import org.springframework.data.mongodb.core.convert.MongoCustomConversions; 052import org.springframework.data.mongodb.core.mapping.MongoMappingContext; 053import org.springframework.data.mongodb.gridfs.GridFsTemplate; 054import org.springframework.util.Assert; 055import org.springframework.util.StringUtils; 056 057/** 058 * {@link EnableAutoConfiguration Auto-configuration} for Spring Data's mongo support. 059 * <p> 060 * Registers a {@link MongoTemplate} and {@link GridFsTemplate} beans if no other beans of 061 * the same type are configured. 062 * <P> 063 * Honors the {@literal spring.data.mongodb.database} property if set, otherwise connects 064 * to the {@literal test} database. 065 * 066 * @author Dave Syer 067 * @author Oliver Gierke 068 * @author Josh Long 069 * @author Phillip Webb 070 * @author EddĂș MelĂ©ndez 071 * @author Stephane Nicoll 072 * @author Christoph Strobl 073 * @since 1.1.0 074 */ 075@Configuration 076@ConditionalOnClass({ MongoClient.class, com.mongodb.client.MongoClient.class, 077 MongoTemplate.class }) 078@Conditional(AnyMongoClientAvailable.class) 079@EnableConfigurationProperties(MongoProperties.class) 080@Import(MongoDataConfiguration.class) 081@AutoConfigureAfter(MongoAutoConfiguration.class) 082public class MongoDataAutoConfiguration { 083 084 private final MongoProperties properties; 085 086 public MongoDataAutoConfiguration(MongoProperties properties) { 087 this.properties = properties; 088 } 089 090 @Bean 091 @ConditionalOnMissingBean(MongoDbFactory.class) 092 public MongoDbFactorySupport<?> mongoDbFactory(ObjectProvider<MongoClient> mongo, 093 ObjectProvider<com.mongodb.client.MongoClient> mongoClient) { 094 MongoClient preferredClient = mongo.getIfAvailable(); 095 if (preferredClient != null) { 096 return new SimpleMongoDbFactory(preferredClient, 097 this.properties.getMongoClientDatabase()); 098 } 099 com.mongodb.client.MongoClient fallbackClient = mongoClient.getIfAvailable(); 100 if (fallbackClient != null) { 101 return new SimpleMongoClientDbFactory(fallbackClient, 102 this.properties.getMongoClientDatabase()); 103 } 104 throw new IllegalStateException("Expected to find at least one MongoDB client."); 105 } 106 107 @Bean 108 @ConditionalOnMissingBean 109 public MongoTemplate mongoTemplate(MongoDbFactory mongoDbFactory, 110 MongoConverter converter) { 111 return new MongoTemplate(mongoDbFactory, converter); 112 } 113 114 @Bean 115 @ConditionalOnMissingBean(MongoConverter.class) 116 public MappingMongoConverter mappingMongoConverter(MongoDbFactory factory, 117 MongoMappingContext context, MongoCustomConversions conversions) { 118 DbRefResolver dbRefResolver = new DefaultDbRefResolver(factory); 119 MappingMongoConverter mappingConverter = new MappingMongoConverter(dbRefResolver, 120 context); 121 mappingConverter.setCustomConversions(conversions); 122 return mappingConverter; 123 } 124 125 @Bean 126 @ConditionalOnMissingBean 127 public GridFsTemplate gridFsTemplate(MongoDbFactory mongoDbFactory, 128 MongoTemplate mongoTemplate) { 129 return new GridFsTemplate( 130 new GridFsMongoDbFactory(mongoDbFactory, this.properties), 131 mongoTemplate.getConverter()); 132 } 133 134 /** 135 * {@link MongoDbFactory} decorator to respect 136 * {@link MongoProperties#getGridFsDatabase()} if set. 137 */ 138 private static class GridFsMongoDbFactory implements MongoDbFactory { 139 140 private final MongoDbFactory mongoDbFactory; 141 142 private final MongoProperties properties; 143 144 GridFsMongoDbFactory(MongoDbFactory mongoDbFactory, MongoProperties properties) { 145 Assert.notNull(mongoDbFactory, "MongoDbFactory must not be null"); 146 Assert.notNull(properties, "Properties must not be null"); 147 this.mongoDbFactory = mongoDbFactory; 148 this.properties = properties; 149 } 150 151 @Override 152 public MongoDatabase getDb() throws DataAccessException { 153 String gridFsDatabase = this.properties.getGridFsDatabase(); 154 if (StringUtils.hasText(gridFsDatabase)) { 155 return this.mongoDbFactory.getDb(gridFsDatabase); 156 } 157 return this.mongoDbFactory.getDb(); 158 } 159 160 @Override 161 public MongoDatabase getDb(String dbName) throws DataAccessException { 162 return this.mongoDbFactory.getDb(dbName); 163 } 164 165 @Override 166 public PersistenceExceptionTranslator getExceptionTranslator() { 167 return this.mongoDbFactory.getExceptionTranslator(); 168 } 169 170 @Override 171 @Deprecated 172 public DB getLegacyDb() { 173 return this.mongoDbFactory.getLegacyDb(); 174 } 175 176 @Override 177 public ClientSession getSession(ClientSessionOptions options) { 178 return this.mongoDbFactory.getSession(options); 179 } 180 181 @Override 182 public MongoDbFactory withSession(ClientSession session) { 183 return this.mongoDbFactory.withSession(session); 184 } 185 186 } 187 188 /** 189 * Check if either a {@link MongoClient com.mongodb.MongoClient} or 190 * {@link com.mongodb.client.MongoClient com.mongodb.client.MongoClient} bean is 191 * available. 192 */ 193 static class AnyMongoClientAvailable extends AnyNestedCondition { 194 195 AnyMongoClientAvailable() { 196 super(ConfigurationPhase.REGISTER_BEAN); 197 } 198 199 @ConditionalOnBean(MongoClient.class) 200 static class PreferredClientAvailable { 201 202 } 203 204 @ConditionalOnBean(com.mongodb.client.MongoClient.class) 205 static class FallbackClientAvailable { 206 207 } 208 209 } 210 211}