40
40
import org .apache .commons .logging .Log ;
41
41
import org .apache .commons .logging .LogFactory ;
42
42
import org .bson .types .ObjectId ;
43
+ import org .springframework .beans .BeansException ;
44
+ import org .springframework .context .ApplicationContext ;
45
+ import org .springframework .context .ApplicationContextAware ;
43
46
import org .springframework .context .ApplicationEventPublisher ;
44
47
import org .springframework .context .ApplicationEventPublisherAware ;
48
+ import org .springframework .context .ConfigurableApplicationContext ;
45
49
import org .springframework .core .convert .ConversionFailedException ;
46
50
import org .springframework .dao .DataAccessException ;
47
51
import org .springframework .dao .DataIntegrityViolationException ;
51
55
import org .springframework .data .document .mongodb .index .IndexDefinition ;
52
56
import org .springframework .data .document .mongodb .mapping .MongoMappingContext ;
53
57
import org .springframework .data .document .mongodb .mapping .MongoPersistentEntity ;
58
+ import org .springframework .data .document .mongodb .mapping .MongoPersistentEntityIndexCreator ;
54
59
import org .springframework .data .document .mongodb .mapping .MongoPersistentProperty ;
55
60
import org .springframework .data .document .mongodb .mapping .event .AfterConvertEvent ;
56
61
import org .springframework .data .document .mongodb .mapping .event .AfterLoadEvent ;
76
81
* @author Mark Pollack
77
82
* @author Oliver Gierke
78
83
*/
79
- public class MongoTemplate implements MongoOperations , ApplicationEventPublisherAware {
84
+ public class MongoTemplate implements MongoOperations , ApplicationContextAware {
80
85
81
86
private static final Log LOGGER = LogFactory .getLog (MongoTemplate .class );
82
87
@@ -99,13 +104,15 @@ public class MongoTemplate implements MongoOperations, ApplicationEventPublisher
99
104
*/
100
105
private boolean slaveOk = false ;
101
106
102
- private final MongoConverter mongoConverter ;
103
- private final MappingContext <? extends MongoPersistentEntity <?>, MongoPersistentProperty > mappingContext ;
104
- private final MongoDbFactory mongoDbFactory ;
105
- private final MongoExceptionTranslator exceptionTranslator = new MongoExceptionTranslator ();
106
- private final QueryMapper mapper ;
107
+ private MongoConverter mongoConverter ;
108
+ private MappingContext <? extends MongoPersistentEntity <?>, MongoPersistentProperty > mappingContext ;
109
+ private MongoDbFactory mongoDbFactory ;
110
+ private MongoExceptionTranslator exceptionTranslator = new MongoExceptionTranslator ();
111
+ private QueryMapper mapper ;
107
112
113
+ private ApplicationContext applicationContext ;
108
114
private ApplicationEventPublisher eventPublisher ;
115
+ private MongoPersistentEntityIndexCreator indexCreator ;
109
116
110
117
/**
111
118
* Constructor used for a basic template configuration
@@ -114,7 +121,7 @@ public class MongoTemplate implements MongoOperations, ApplicationEventPublisher
114
121
* @param databaseName
115
122
*/
116
123
public MongoTemplate (Mongo mongo , String databaseName ) {
117
- this (new MongoDbFactoryBean (mongo , databaseName ));
124
+ this (new MongoDbFactoryBean (mongo , databaseName ), null , null , null );
118
125
}
119
126
120
127
/**
@@ -126,7 +133,7 @@ public MongoTemplate(Mongo mongo, String databaseName) {
126
133
* @param mongoConverter
127
134
*/
128
135
public MongoTemplate (Mongo mongo , String databaseName , MongoConverter mongoConverter ) {
129
- this (new MongoDbFactoryBean (mongo , databaseName ), mongoConverter );
136
+ this (new MongoDbFactoryBean (mongo , databaseName ), mongoConverter , null , null );
130
137
}
131
138
132
139
/**
@@ -135,7 +142,7 @@ public MongoTemplate(Mongo mongo, String databaseName, MongoConverter mongoConve
135
142
* @param mongoDbFactory
136
143
*/
137
144
public MongoTemplate (MongoDbFactory mongoDbFactory ) {
138
- this (mongoDbFactory , null );
145
+ this (mongoDbFactory , null , null , null );
139
146
}
140
147
141
148
/**
@@ -162,37 +169,52 @@ public MongoTemplate(MongoDbFactory mongoDbFactory, MongoConverter mongoConverte
162
169
WriteConcern writeConcern ,
163
170
WriteResultChecking writeResultChecking ) {
164
171
Assert .notNull (mongoDbFactory );
165
-
172
+ // Always need a MongoDbFactory for obtaining instances of DB
166
173
this .mongoDbFactory = mongoDbFactory ;
167
- this . mongoConverter = mongoConverter == null ? getDefaultMongoConverter () : mongoConverter ;
168
- this . writeConcern = writeConcern ;
169
-
170
- if ( this . mongoConverter instanceof MappingMongoConverter ) {
171
- initializeMappingMongoConverter (( MappingMongoConverter ) this .mongoConverter ) ;
174
+ // Conversion of DBObject to POJO handled either custom or by default (MappingMongoConverter)
175
+ if ( null == mongoConverter ) {
176
+ this . mongoConverter = getDefaultMongoConverter ();
177
+ } else {
178
+ this .mongoConverter = mongoConverter ;
172
179
}
173
-
174
- this .mappingContext = this .mongoConverter .getMappingContext ();
175
- this .mapper = new QueryMapper (this .mongoConverter );
176
-
180
+ // We always have a mapping context in the converter, whether it's a simple one or not
181
+ mappingContext = this .mongoConverter .getMappingContext ();
182
+ // We create indexes based on mapping events
183
+ if (null != mappingContext && mappingContext instanceof MongoMappingContext ) {
184
+ indexCreator = new MongoPersistentEntityIndexCreator ((MongoMappingContext ) mappingContext , mongoDbFactory );
185
+ eventPublisher = new MongoMappingEventPublisher (indexCreator );
186
+ if (mappingContext instanceof ApplicationEventPublisherAware ) {
187
+ ((ApplicationEventPublisherAware ) mappingContext ).setApplicationEventPublisher (eventPublisher );
188
+ }
189
+ }
190
+ // WriteConcern
191
+ this .writeConcern = writeConcern ;
192
+ // For converting ID names and values throughout Query objects
193
+ mapper = new QueryMapper (this .mongoConverter );
194
+ // Track WriteResults?
177
195
if (writeResultChecking != null ) {
178
196
this .writeResultChecking = writeResultChecking ;
179
197
}
180
198
181
- if (this .mappingContext instanceof MongoMappingContext ) {
182
- this .eventPublisher = new MongoMappingEventPublisher ((MongoMappingContext ) mappingContext , mongoDbFactory );
183
- }
184
-
185
199
}
186
200
187
201
private final MongoConverter getDefaultMongoConverter () {
188
202
//ToDo: maybe add some additional configurations to this very basic one
189
- MappingMongoConverter converter = new MappingMongoConverter (new MongoMappingContext ());
203
+ MappingMongoConverter converter = new MappingMongoConverter (mongoDbFactory , new MongoMappingContext ());
190
204
converter .afterPropertiesSet ();
191
205
return converter ;
192
206
}
193
207
194
- public void setApplicationEventPublisher (ApplicationEventPublisher applicationEventPublisher ) {
195
- this .eventPublisher = applicationEventPublisher ;
208
+ public void setApplicationContext (ApplicationContext applicationContext ) throws BeansException {
209
+ this .applicationContext = applicationContext ;
210
+ String [] beans = applicationContext .getBeanNamesForType (MongoPersistentEntityIndexCreator .class );
211
+ if ((null == beans || beans .length == 0 ) && applicationContext instanceof ConfigurableApplicationContext ) {
212
+ ((ConfigurableApplicationContext ) applicationContext ).addApplicationListener (indexCreator );
213
+ }
214
+ eventPublisher = applicationContext ;
215
+ if (mappingContext instanceof ApplicationEventPublisherAware ) {
216
+ ((ApplicationEventPublisherAware ) mappingContext ).setApplicationEventPublisher (eventPublisher );
217
+ }
196
218
}
197
219
198
220
/**
@@ -213,9 +235,13 @@ public MongoDbFactory getDbFactory() {
213
235
return this .mongoDbFactory ;
214
236
}
215
237
238
+ public MappingContext <? extends MongoPersistentEntity <?>, MongoPersistentProperty > getMappingContext () {
239
+ return mappingContext ;
240
+ }
241
+
216
242
/* (non-Javadoc)
217
- * @see org.springframework.data.document.mongodb.MongoOperations#getDefaultCollectionName()
218
- */
243
+ * @see org.springframework.data.document.mongodb.MongoOperations#getDefaultCollectionName()
244
+ */
219
245
public String getCollectionName (Class <?> clazz ) {
220
246
return this .determineCollectionName (clazz );
221
247
}
@@ -417,12 +443,12 @@ public DBCursor prepare(DBCursor cursor) {
417
443
public <T > List <T > find (String collectionName , Query query , Class <T > targetClass , CursorPreparer preparer ) {
418
444
return doFind (collectionName , query .getQueryObject (), query .getFieldsObject (), targetClass , preparer );
419
445
}
420
-
446
+
421
447
public <T > T findById (Object id , Class <T > targetClass ) {
422
448
MongoPersistentEntity <?> persistentEntity = mappingContext .getPersistentEntity (targetClass );
423
449
return findById (persistentEntity .getCollection (), id , targetClass );
424
450
}
425
-
451
+
426
452
public <T > T findById (String collectionName , Object id , Class <T > targetClass ) {
427
453
MongoPersistentEntity <?> persistentEntity = mappingContext .getPersistentEntity (targetClass );
428
454
MongoPersistentProperty idProperty = persistentEntity .getIdProperty ();
@@ -455,15 +481,15 @@ public void insert(Object objectToSave) {
455
481
public void insert (String collectionName , Object objectToSave ) {
456
482
doInsert (collectionName , objectToSave , this .mongoConverter );
457
483
}
458
-
484
+
459
485
/**
460
- * Prepare the collection before any processing is done using it. This allows a convenient way to apply
486
+ * Prepare the collection before any processing is done using it. This allows a convenient way to apply
461
487
* settings like slaveOk() etc. Can be overridden in sub-classes.
462
- *
488
+ *
463
489
* @param collection
464
490
*/
465
491
protected void prepareCollection (DBCollection collection ) {
466
- if (this .slaveOk ) {
492
+ if (this .slaveOk ) {
467
493
collection .slaveOk ();
468
494
}
469
495
}
@@ -975,7 +1001,7 @@ protected Object getIdValue(Object object) {
975
1001
throw new MappingException (e .getMessage (), e );
976
1002
}
977
1003
}
978
-
1004
+
979
1005
protected String getIdPropertyName (Object object ) {
980
1006
MongoPersistentEntity <?> persistentEntity = mappingContext .getPersistentEntity (object .getClass ());
981
1007
MongoPersistentProperty idProperty = persistentEntity .getIdProperty ();
@@ -1027,18 +1053,15 @@ private DBCollection getAndPrepareCollection(DB db, String collectionName) {
1027
1053
* <li>Execute the given {@link ConnectionCallback} for a {@link DBObject}.</li>
1028
1054
* <li>Apply the given {@link DbObjectCallback} to each of the {@link DBObject}s to obtain the result.</li>
1029
1055
* <ol>
1030
- *
1056
+ *
1031
1057
* @param <T>
1032
- * @param collectionCallback
1033
- * the callback to retrieve the {@link DBObject} with
1034
- * @param objectCallback
1035
- * the {@link DbObjectCallback} to transform {@link DBObject}s into the actual domain type
1036
- * @param collectionName
1037
- * the collection to be queried
1058
+ * @param collectionCallback the callback to retrieve the {@link DBObject} with
1059
+ * @param objectCallback the {@link DbObjectCallback} to transform {@link DBObject}s into the actual domain type
1060
+ * @param collectionName the collection to be queried
1038
1061
* @return
1039
1062
*/
1040
1063
private <T > T executeFindOneInternal (CollectionCallback <DBObject > collectionCallback , DbObjectCallback <T > objectCallback ,
1041
- String collectionName ) {
1064
+ String collectionName ) {
1042
1065
1043
1066
try {
1044
1067
T result = objectCallback .doWith (collectionCallback .doInCollection (getAndPrepareCollection (getDb (), collectionName )));
@@ -1058,20 +1081,16 @@ private <T> T executeFindOneInternal(CollectionCallback<DBObject> collectionCall
1058
1081
* <li>Iterate over the {@link DBCursor} and applies the given {@link DbObjectCallback} to each of the
1059
1082
* {@link DBObject}s collecting the actual result {@link List}.</li>
1060
1083
* <ol>
1061
- *
1084
+ *
1062
1085
* @param <T>
1063
- * @param collectionCallback
1064
- * the callback to retrieve the {@link DBCursor} with
1065
- * @param preparer
1066
- * the {@link CursorPreparer} to potentially modify the {@link DBCursor} before ireating over it
1067
- * @param objectCallback
1068
- * the {@link DbObjectCallback} to transform {@link DBObject}s into the actual domain type
1069
- * @param collectionName
1070
- * the collection to be queried
1086
+ * @param collectionCallback the callback to retrieve the {@link DBCursor} with
1087
+ * @param preparer the {@link CursorPreparer} to potentially modify the {@link DBCursor} before ireating over it
1088
+ * @param objectCallback the {@link DbObjectCallback} to transform {@link DBObject}s into the actual domain type
1089
+ * @param collectionName the collection to be queried
1071
1090
* @return
1072
1091
*/
1073
1092
private <T > List <T > executeFindMultiInternal (CollectionCallback <DBCursor > collectionCallback , CursorPreparer preparer ,
1074
- DbObjectCallback <T > objectCallback , String collectionName ) {
1093
+ DbObjectCallback <T > objectCallback , String collectionName ) {
1075
1094
1076
1095
try {
1077
1096
DBCursor cursor = collectionCallback .doInCollection (getAndPrepareCollection (getDb (), collectionName ));
@@ -1179,11 +1198,6 @@ private RuntimeException potentiallyConvertRuntimeException(RuntimeException ex)
1179
1198
return resolved == null ? ex : resolved ;
1180
1199
}
1181
1200
1182
- private void initializeMappingMongoConverter (MappingMongoConverter converter ) {
1183
- converter .setMongo (this .mongoDbFactory .getMongo ());
1184
- converter .setDefaultDatabase (this .mongoDbFactory .getDatabaseName ());
1185
- }
1186
-
1187
1201
/**
1188
1202
* Simple {@link CollectionCallback} that takes a query {@link DBObject} plus an optional fields specification
1189
1203
* {@link DBObject} and executes that against the {@link DBCollection}.
0 commit comments