Skip to content

Commit 5e969de

Browse files
DATAKV-91 - Add support for sending application events.
We now allow definition of event types to be published via the application context.
1 parent dc1cc85 commit 5e969de

File tree

5 files changed

+526
-17
lines changed

5 files changed

+526
-17
lines changed

src/main/java/org/springframework/data/keyvalue/core/KeyValueAdapter.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,4 +101,10 @@ public interface KeyValueAdapter extends DisposableBean {
101101
* @return
102102
*/
103103
long count(KeyValueQuery<?> query, Serializable keyspace);
104+
105+
/**
106+
* @param keyspace
107+
* @return true if {@literal keyspace} already present in adapter.
108+
*/
109+
boolean hasKeyspace(Serializable keyspace);
104110
}

src/main/java/org/springframework/data/keyvalue/core/KeyValueTemplate.java

Lines changed: 88 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2014 the original author or authors.
2+
* Copyright 2014-2015 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -20,21 +20,30 @@
2020
import java.io.Serializable;
2121
import java.util.ArrayList;
2222
import java.util.Collection;
23+
import java.util.Collections;
24+
import java.util.HashSet;
2325
import java.util.List;
26+
import java.util.Set;
2427
import java.util.concurrent.ConcurrentHashMap;
2528

29+
import org.springframework.beans.BeansException;
30+
import org.springframework.context.ApplicationContext;
31+
import org.springframework.context.ApplicationContextAware;
32+
import org.springframework.context.ApplicationEventPublisher;
2633
import org.springframework.dao.DataAccessException;
2734
import org.springframework.dao.DuplicateKeyException;
2835
import org.springframework.dao.InvalidDataAccessApiUsageException;
2936
import org.springframework.dao.support.PersistenceExceptionTranslator;
3037
import org.springframework.data.domain.Sort;
38+
import org.springframework.data.keyvalue.core.event.KeyValueEvent;
3139
import org.springframework.data.keyvalue.core.mapping.context.KeyValueMappingContext;
3240
import org.springframework.data.keyvalue.core.query.KeyValueQuery;
3341
import org.springframework.data.mapping.PersistentEntity;
3442
import org.springframework.data.mapping.PersistentProperty;
3543
import org.springframework.data.mapping.context.MappingContext;
3644
import org.springframework.util.Assert;
3745
import org.springframework.util.ClassUtils;
46+
import org.springframework.util.CollectionUtils;
3847
import org.springframework.util.StringUtils;
3948

4049
/**
@@ -43,14 +52,16 @@
4352
* @author Christoph Strobl
4453
* @author Oliver Gierke
4554
*/
46-
public class KeyValueTemplate implements KeyValueOperations {
55+
public class KeyValueTemplate implements KeyValueOperations, ApplicationContextAware {
4756

4857
private static final PersistenceExceptionTranslator DEFAULT_PERSISTENCE_EXCEPTION_TRANSLATOR = new KeyValuePersistenceExceptionTranslator();
4958

5059
private final KeyValueAdapter adapter;
5160
private final ConcurrentHashMap<Class<?>, String> keySpaceCache = new ConcurrentHashMap<Class<?>, String>();
5261
private final MappingContext<? extends PersistentEntity<?, ? extends PersistentProperty<?>>, ? extends PersistentProperty<?>> mappingContext;
5362
private final IdentifierGenerator identifierGenerator;
63+
private ApplicationEventPublisher eventPublisher;
64+
private Set<KeyValueEvent.Type> eventTypesToPublish = new HashSet<KeyValueEvent.Type>(4);
5465
private PersistenceExceptionTranslator exceptionTranslator = DEFAULT_PERSISTENCE_EXCEPTION_TRANSLATOR;
5566

5667
/**
@@ -109,22 +120,26 @@ public void insert(final Serializable id, final Object objectToInsert) {
109120
Assert.notNull(id, "Id for object to be inserted must not be null!");
110121
Assert.notNull(objectToInsert, "Object to be inserted must not be null!");
111122

123+
final String keyspace = resolveKeySpace(objectToInsert.getClass());
124+
125+
potentiallyPublishEvent(KeyValueEvent.beforeInsert(this, keyspace, id, objectToInsert));
126+
112127
execute(new KeyValueCallback<Void>() {
113128

114129
@Override
115130
public Void doInKeyValue(KeyValueAdapter adapter) {
116131

117-
String typeKey = resolveKeySpace(objectToInsert.getClass());
118-
119-
if (adapter.contains(id, typeKey)) {
132+
if (adapter.contains(id, keyspace)) {
120133
throw new DuplicateKeyException(String.format(
121134
"Cannot insert existing object with id %s!. Please use update.", id));
122135
}
123136

124-
adapter.put(id, objectToInsert, typeKey);
137+
adapter.put(id, objectToInsert, keyspace);
125138
return null;
126139
}
127140
});
141+
142+
potentiallyPublishEvent(KeyValueEvent.afterInsert(this, keyspace, id, objectToInsert));
128143
}
129144

130145
/*
@@ -156,14 +171,20 @@ public void update(final Serializable id, final Object objectToUpdate) {
156171
Assert.notNull(id, "Id for object to be inserted must not be null!");
157172
Assert.notNull(objectToUpdate, "Object to be updated must not be null!");
158173

174+
final String keyspace = resolveKeySpace(objectToUpdate.getClass());
175+
176+
potentiallyPublishEvent(KeyValueEvent.beforeUpdate(this, keyspace, id, objectToUpdate));
177+
159178
execute(new KeyValueCallback<Void>() {
160179

161180
@Override
162181
public Void doInKeyValue(KeyValueAdapter adapter) {
163-
adapter.put(id, objectToUpdate, resolveKeySpace(objectToUpdate.getClass()));
182+
adapter.put(id, objectToUpdate, keyspace);
164183
return null;
165184
}
166185
});
186+
187+
potentiallyPublishEvent(KeyValueEvent.afterUpdate(this, keyspace, id, objectToUpdate));
167188
}
168189

169190
/*
@@ -209,13 +230,17 @@ public <T> T findById(final Serializable id, final Class<T> type) {
209230
Assert.notNull(id, "Id for object to be inserted must not be null!");
210231
Assert.notNull(type, "Type to fetch must not be null!");
211232

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>() {
213238

214239
@SuppressWarnings("unchecked")
215240
@Override
216241
public T doInKeyValue(KeyValueAdapter adapter) {
217242

218-
Object result = adapter.get(id, resolveKeySpace(type));
243+
Object result = adapter.get(id, keyspace);
219244

220245
if (result == null || getKeySpace(type) == null || typeCheck(type, result)) {
221246
return (T) result;
@@ -224,6 +249,10 @@ public T doInKeyValue(KeyValueAdapter adapter) {
224249
return null;
225250
}
226251
});
252+
253+
potentiallyPublishEvent(KeyValueEvent.afterGet(this, keyspace, id, result));
254+
255+
return result;
227256
}
228257

229258
/*
@@ -235,17 +264,21 @@ public void delete(final Class<?> type) {
235264

236265
Assert.notNull(type, "Type to delete must not be null!");
237266

238-
final String typeKey = resolveKeySpace(type);
267+
final String keyspace = resolveKeySpace(type);
268+
269+
potentiallyPublishEvent(KeyValueEvent.beforeDelete(this, keyspace));
239270

240271
execute(new KeyValueCallback<Void>() {
241272

242273
@Override
243274
public Void doInKeyValue(KeyValueAdapter adapter) {
244275

245-
adapter.deleteAllOf(typeKey);
276+
adapter.deleteAllOf(keyspace);
246277
return null;
247278
}
248279
});
280+
281+
potentiallyPublishEvent(KeyValueEvent.afterDelete(this, keyspace));
249282
}
250283

251284
/*
@@ -272,14 +305,22 @@ public <T> T delete(final Serializable id, final Class<T> type) {
272305
Assert.notNull(id, "Id for object to be inserted must not be null!");
273306
Assert.notNull(type, "Type to delete must not be null!");
274307

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>() {
276313

277314
@SuppressWarnings("unchecked")
278315
@Override
279316
public T doInKeyValue(KeyValueAdapter adapter) {
280-
return (T) adapter.delete(id, resolveKeySpace(type));
317+
return (T) adapter.delete(id, keyspace);
281318
}
282319
});
320+
321+
potentiallyPublishEvent(KeyValueEvent.afterDelete(this, keyspace, id, result));
322+
323+
return result;
283324
}
284325

285326
/*
@@ -416,14 +457,37 @@ public void setExceptionTranslator(PersistenceExceptionTranslator exceptionTrans
416457
this.exceptionTranslator = exceptionTranslator;
417458
}
418459

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+
419483
protected String resolveKeySpace(Class<?> type) {
420484

421485
Class<?> userClass = ClassUtils.getUserClass(type);
422486

423-
String potentialAlias = keySpaceCache.get(userClass);
487+
String potentialKeySpace = keySpaceCache.get(userClass);
424488

425-
if (potentialAlias != null) {
426-
return potentialAlias;
489+
if (potentialKeySpace != null) {
490+
return potentialKeySpace;
427491
}
428492

429493
String keySpaceString = null;
@@ -450,4 +514,12 @@ private RuntimeException resolveExceptionIfPossible(RuntimeException e) {
450514
DataAccessException translatedException = exceptionTranslator.translateExceptionIfPossible(e);
451515
return translatedException != null ? translatedException : e;
452516
}
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+
}
453525
}

0 commit comments

Comments
 (0)