1
1
/*
2
- * Copyright 2014 the original author or authors.
2
+ * Copyright 2014-2015 the original author or authors.
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
20
20
import java .io .Serializable ;
21
21
import java .util .ArrayList ;
22
22
import java .util .Collection ;
23
+ import java .util .Collections ;
24
+ import java .util .HashSet ;
23
25
import java .util .List ;
26
+ import java .util .Set ;
24
27
import java .util .concurrent .ConcurrentHashMap ;
25
28
29
+ import org .springframework .beans .BeansException ;
30
+ import org .springframework .context .ApplicationContext ;
31
+ import org .springframework .context .ApplicationContextAware ;
32
+ import org .springframework .context .ApplicationEventPublisher ;
26
33
import org .springframework .dao .DataAccessException ;
27
34
import org .springframework .dao .DuplicateKeyException ;
28
35
import org .springframework .dao .InvalidDataAccessApiUsageException ;
29
36
import org .springframework .dao .support .PersistenceExceptionTranslator ;
30
37
import org .springframework .data .domain .Sort ;
38
+ import org .springframework .data .keyvalue .core .event .KeyValueEvent ;
31
39
import org .springframework .data .keyvalue .core .mapping .context .KeyValueMappingContext ;
32
40
import org .springframework .data .keyvalue .core .query .KeyValueQuery ;
33
41
import org .springframework .data .mapping .PersistentEntity ;
34
42
import org .springframework .data .mapping .PersistentProperty ;
35
43
import org .springframework .data .mapping .context .MappingContext ;
36
44
import org .springframework .util .Assert ;
37
45
import org .springframework .util .ClassUtils ;
46
+ import org .springframework .util .CollectionUtils ;
38
47
import org .springframework .util .StringUtils ;
39
48
40
49
/**
43
52
* @author Christoph Strobl
44
53
* @author Oliver Gierke
45
54
*/
46
- public class KeyValueTemplate implements KeyValueOperations {
55
+ public class KeyValueTemplate implements KeyValueOperations , ApplicationContextAware {
47
56
48
57
private static final PersistenceExceptionTranslator DEFAULT_PERSISTENCE_EXCEPTION_TRANSLATOR = new KeyValuePersistenceExceptionTranslator ();
49
58
50
59
private final KeyValueAdapter adapter ;
51
60
private final ConcurrentHashMap <Class <?>, String > keySpaceCache = new ConcurrentHashMap <Class <?>, String >();
52
61
private final MappingContext <? extends PersistentEntity <?, ? extends PersistentProperty <?>>, ? extends PersistentProperty <?>> mappingContext ;
53
62
private final IdentifierGenerator identifierGenerator ;
63
+ private ApplicationEventPublisher eventPublisher ;
64
+ private Set <KeyValueEvent .Type > eventTypesToPublish = new HashSet <KeyValueEvent .Type >(4 );
54
65
private PersistenceExceptionTranslator exceptionTranslator = DEFAULT_PERSISTENCE_EXCEPTION_TRANSLATOR ;
55
66
56
67
/**
@@ -109,22 +120,26 @@ public void insert(final Serializable id, final Object objectToInsert) {
109
120
Assert .notNull (id , "Id for object to be inserted must not be null!" );
110
121
Assert .notNull (objectToInsert , "Object to be inserted must not be null!" );
111
122
123
+ final String keyspace = resolveKeySpace (objectToInsert .getClass ());
124
+
125
+ potentiallyPublishEvent (KeyValueEvent .beforeInsert (this , keyspace , id , objectToInsert ));
126
+
112
127
execute (new KeyValueCallback <Void >() {
113
128
114
129
@ Override
115
130
public Void doInKeyValue (KeyValueAdapter adapter ) {
116
131
117
- String typeKey = resolveKeySpace (objectToInsert .getClass ());
118
-
119
- if (adapter .contains (id , typeKey )) {
132
+ if (adapter .contains (id , keyspace )) {
120
133
throw new DuplicateKeyException (String .format (
121
134
"Cannot insert existing object with id %s!. Please use update." , id ));
122
135
}
123
136
124
- adapter .put (id , objectToInsert , typeKey );
137
+ adapter .put (id , objectToInsert , keyspace );
125
138
return null ;
126
139
}
127
140
});
141
+
142
+ potentiallyPublishEvent (KeyValueEvent .afterInsert (this , keyspace , id , objectToInsert ));
128
143
}
129
144
130
145
/*
@@ -156,14 +171,20 @@ public void update(final Serializable id, final Object objectToUpdate) {
156
171
Assert .notNull (id , "Id for object to be inserted must not be null!" );
157
172
Assert .notNull (objectToUpdate , "Object to be updated must not be null!" );
158
173
174
+ final String keyspace = resolveKeySpace (objectToUpdate .getClass ());
175
+
176
+ potentiallyPublishEvent (KeyValueEvent .beforeUpdate (this , keyspace , id , objectToUpdate ));
177
+
159
178
execute (new KeyValueCallback <Void >() {
160
179
161
180
@ Override
162
181
public Void doInKeyValue (KeyValueAdapter adapter ) {
163
- adapter .put (id , objectToUpdate , resolveKeySpace ( objectToUpdate . getClass ()) );
182
+ adapter .put (id , objectToUpdate , keyspace );
164
183
return null ;
165
184
}
166
185
});
186
+
187
+ potentiallyPublishEvent (KeyValueEvent .afterUpdate (this , keyspace , id , objectToUpdate ));
167
188
}
168
189
169
190
/*
@@ -209,13 +230,17 @@ public <T> T findById(final Serializable id, final Class<T> type) {
209
230
Assert .notNull (id , "Id for object to be inserted must not be null!" );
210
231
Assert .notNull (type , "Type to fetch must not be null!" );
211
232
212
- return execute (new KeyValueCallback <T >() {
233
+ final String keyspace = resolveKeySpace (type );
234
+
235
+ potentiallyPublishEvent (KeyValueEvent .beforeGet (this , keyspace , id ));
236
+
237
+ T result = execute (new KeyValueCallback <T >() {
213
238
214
239
@ SuppressWarnings ("unchecked" )
215
240
@ Override
216
241
public T doInKeyValue (KeyValueAdapter adapter ) {
217
242
218
- Object result = adapter .get (id , resolveKeySpace ( type ) );
243
+ Object result = adapter .get (id , keyspace );
219
244
220
245
if (result == null || getKeySpace (type ) == null || typeCheck (type , result )) {
221
246
return (T ) result ;
@@ -224,6 +249,10 @@ public T doInKeyValue(KeyValueAdapter adapter) {
224
249
return null ;
225
250
}
226
251
});
252
+
253
+ potentiallyPublishEvent (KeyValueEvent .afterGet (this , keyspace , id , result ));
254
+
255
+ return result ;
227
256
}
228
257
229
258
/*
@@ -235,17 +264,21 @@ public void delete(final Class<?> type) {
235
264
236
265
Assert .notNull (type , "Type to delete must not be null!" );
237
266
238
- final String typeKey = resolveKeySpace (type );
267
+ final String keyspace = resolveKeySpace (type );
268
+
269
+ potentiallyPublishEvent (KeyValueEvent .beforeDelete (this , keyspace ));
239
270
240
271
execute (new KeyValueCallback <Void >() {
241
272
242
273
@ Override
243
274
public Void doInKeyValue (KeyValueAdapter adapter ) {
244
275
245
- adapter .deleteAllOf (typeKey );
276
+ adapter .deleteAllOf (keyspace );
246
277
return null ;
247
278
}
248
279
});
280
+
281
+ potentiallyPublishEvent (KeyValueEvent .afterDelete (this , keyspace ));
249
282
}
250
283
251
284
/*
@@ -272,14 +305,22 @@ public <T> T delete(final Serializable id, final Class<T> type) {
272
305
Assert .notNull (id , "Id for object to be inserted must not be null!" );
273
306
Assert .notNull (type , "Type to delete must not be null!" );
274
307
275
- return execute (new KeyValueCallback <T >() {
308
+ final String keyspace = resolveKeySpace (type );
309
+
310
+ potentiallyPublishEvent (KeyValueEvent .beforeDelete (this , keyspace , id ));
311
+
312
+ T result = execute (new KeyValueCallback <T >() {
276
313
277
314
@ SuppressWarnings ("unchecked" )
278
315
@ Override
279
316
public T doInKeyValue (KeyValueAdapter adapter ) {
280
- return (T ) adapter .delete (id , resolveKeySpace ( type ) );
317
+ return (T ) adapter .delete (id , keyspace );
281
318
}
282
319
});
320
+
321
+ potentiallyPublishEvent (KeyValueEvent .afterDelete (this , keyspace , id , result ));
322
+
323
+ return result ;
283
324
}
284
325
285
326
/*
@@ -416,14 +457,37 @@ public void setExceptionTranslator(PersistenceExceptionTranslator exceptionTrans
416
457
this .exceptionTranslator = exceptionTranslator ;
417
458
}
418
459
460
+ /*
461
+ * (non-Javadoc)
462
+ * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
463
+ */
464
+ @ Override
465
+ public void setApplicationContext (ApplicationContext applicationContext ) throws BeansException {
466
+ eventPublisher = applicationContext ;
467
+ }
468
+
469
+ /**
470
+ * Define the event types to publish via {@link ApplicationEventPublisher}.
471
+ *
472
+ * @param eventTypesToPublish use {@literal null} or {@link Collections#emptySet()} to disable publishing.
473
+ */
474
+ public void setEventTypesToPublish (Set <KeyValueEvent .Type > eventTypesToPublish ) {
475
+
476
+ this .eventTypesToPublish .clear ();
477
+
478
+ if (!CollectionUtils .isEmpty (eventTypesToPublish )) {
479
+ this .eventTypesToPublish .addAll (eventTypesToPublish );
480
+ }
481
+ }
482
+
419
483
protected String resolveKeySpace (Class <?> type ) {
420
484
421
485
Class <?> userClass = ClassUtils .getUserClass (type );
422
486
423
- String potentialAlias = keySpaceCache .get (userClass );
487
+ String potentialKeySpace = keySpaceCache .get (userClass );
424
488
425
- if (potentialAlias != null ) {
426
- return potentialAlias ;
489
+ if (potentialKeySpace != null ) {
490
+ return potentialKeySpace ;
427
491
}
428
492
429
493
String keySpaceString = null ;
@@ -450,4 +514,12 @@ private RuntimeException resolveExceptionIfPossible(RuntimeException e) {
450
514
DataAccessException translatedException = exceptionTranslator .translateExceptionIfPossible (e );
451
515
return translatedException != null ? translatedException : e ;
452
516
}
517
+
518
+ private void potentiallyPublishEvent (KeyValueEvent <?> event ) {
519
+
520
+ if (eventPublisher != null
521
+ && (eventTypesToPublish .contains (event .getType ()) || eventTypesToPublish .contains (KeyValueEvent .Type .ANY ))) {
522
+ eventPublisher .publishEvent (event );
523
+ }
524
+ }
453
525
}
0 commit comments