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
/*
@@ -235,17 +256,21 @@ public void delete(final Class<?> type) {
235
256
236
257
Assert .notNull (type , "Type to delete must not be null!" );
237
258
238
- final String typeKey = resolveKeySpace (type );
259
+ final String keyspace = resolveKeySpace (type );
260
+
261
+ potentiallyPublishEvent (KeyValueEvent .beforeDelete (this , keyspace ));
239
262
240
263
execute (new KeyValueCallback <Void >() {
241
264
242
265
@ Override
243
266
public Void doInKeyValue (KeyValueAdapter adapter ) {
244
267
245
- adapter .deleteAllOf (typeKey );
268
+ adapter .deleteAllOf (keyspace );
246
269
return null ;
247
270
}
248
271
});
272
+
273
+ potentiallyPublishEvent (KeyValueEvent .afterDelete (this , keyspace ));
249
274
}
250
275
251
276
/*
@@ -272,14 +297,22 @@ public <T> T delete(final Serializable id, final Class<T> type) {
272
297
Assert .notNull (id , "Id for object to be inserted must not be null!" );
273
298
Assert .notNull (type , "Type to delete must not be null!" );
274
299
275
- return execute (new KeyValueCallback <T >() {
300
+ final String keyspace = resolveKeySpace (type );
301
+
302
+ potentiallyPublishEvent (KeyValueEvent .beforeDelete (this , keyspace , id ));
303
+
304
+ T result = execute (new KeyValueCallback <T >() {
276
305
277
306
@ SuppressWarnings ("unchecked" )
278
307
@ Override
279
308
public T doInKeyValue (KeyValueAdapter adapter ) {
280
- return (T ) adapter .delete (id , resolveKeySpace ( type ) );
309
+ return (T ) adapter .delete (id , keyspace );
281
310
}
282
311
});
312
+
313
+ potentiallyPublishEvent (KeyValueEvent .afterDelete (this , keyspace , id , result ));
314
+
315
+ return result ;
283
316
}
284
317
285
318
/*
@@ -416,14 +449,37 @@ public void setExceptionTranslator(PersistenceExceptionTranslator exceptionTrans
416
449
this .exceptionTranslator = exceptionTranslator ;
417
450
}
418
451
452
+ /*
453
+ * (non-Javadoc)
454
+ * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
455
+ */
456
+ @ Override
457
+ public void setApplicationContext (ApplicationContext applicationContext ) throws BeansException {
458
+ eventPublisher = applicationContext ;
459
+ }
460
+
461
+ /**
462
+ * Define the event types to publish via {@link ApplicationEventPublisher}.
463
+ *
464
+ * @param eventTypesToPublish use {@literal null} or {@link Collections#emptySet()} to disable publishing.
465
+ */
466
+ public void setEventTypesToPublish (Set <KeyValueEvent .Type > eventTypesToPublish ) {
467
+
468
+ this .eventTypesToPublish .clear ();
469
+
470
+ if (!CollectionUtils .isEmpty (eventTypesToPublish )) {
471
+ this .eventTypesToPublish .addAll (eventTypesToPublish );
472
+ }
473
+ }
474
+
419
475
protected String resolveKeySpace (Class <?> type ) {
420
476
421
477
Class <?> userClass = ClassUtils .getUserClass (type );
422
478
423
- String potentialAlias = keySpaceCache .get (userClass );
479
+ String potentialKeySpace = keySpaceCache .get (userClass );
424
480
425
- if (potentialAlias != null ) {
426
- return potentialAlias ;
481
+ if (potentialKeySpace != null ) {
482
+ return potentialKeySpace ;
427
483
}
428
484
429
485
String keySpaceString = null ;
@@ -450,4 +506,11 @@ private RuntimeException resolveExceptionIfPossible(RuntimeException e) {
450
506
DataAccessException translatedException = exceptionTranslator .translateExceptionIfPossible (e );
451
507
return translatedException != null ? translatedException : e ;
452
508
}
509
+
510
+ private void potentiallyPublishEvent (KeyValueEvent <?> event ) {
511
+
512
+ if (eventPublisher != null && eventTypesToPublish .contains (event .getType ())) {
513
+ eventPublisher .publishEvent (event );
514
+ }
515
+ }
453
516
}
0 commit comments