diff --git a/pom.xml b/pom.xml
index 2917aeb0..d85d8420 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
org.springframework.data
spring-data-keyvalue
- 0.1.0.BUILD-SNAPSHOT
+ 0.1.0.DATAKV-91-SNAPSHOT
Spring Data KeyValue
diff --git a/src/main/java/org/springframework/data/keyvalue/core/KeyValueAdapter.java b/src/main/java/org/springframework/data/keyvalue/core/KeyValueAdapter.java
index bfc019f7..1c0a0eef 100644
--- a/src/main/java/org/springframework/data/keyvalue/core/KeyValueAdapter.java
+++ b/src/main/java/org/springframework/data/keyvalue/core/KeyValueAdapter.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014 the original author or authors.
+ * Copyright 2014-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -101,4 +101,12 @@ public interface KeyValueAdapter extends DisposableBean {
* @return
*/
long count(KeyValueQuery> query, Serializable keyspace);
+
+ /**
+ * Check if values from the given keyspace are contained in the underlying key-value store.
+ *
+ * @param keyspace
+ * @return true if {@literal keyspace} already present in adapter.
+ */
+ boolean hasKeyspace(Serializable keyspace);
}
diff --git a/src/main/java/org/springframework/data/keyvalue/core/KeyValueTemplate.java b/src/main/java/org/springframework/data/keyvalue/core/KeyValueTemplate.java
index 5d897c47..6d677226 100644
--- a/src/main/java/org/springframework/data/keyvalue/core/KeyValueTemplate.java
+++ b/src/main/java/org/springframework/data/keyvalue/core/KeyValueTemplate.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014 the original author or authors.
+ * Copyright 2014-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,14 +20,22 @@
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.context.ApplicationEventPublisher;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.data.domain.Sort;
+import org.springframework.data.keyvalue.core.event.KeyValueEvent;
import org.springframework.data.keyvalue.core.mapping.context.KeyValueMappingContext;
import org.springframework.data.keyvalue.core.query.KeyValueQuery;
import org.springframework.data.mapping.PersistentEntity;
@@ -35,6 +43,7 @@
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
+import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
/**
@@ -42,8 +51,9 @@
*
* @author Christoph Strobl
* @author Oliver Gierke
+ * @author Thomas Darimont
*/
-public class KeyValueTemplate implements KeyValueOperations {
+public class KeyValueTemplate implements KeyValueOperations, ApplicationContextAware {
private static final PersistenceExceptionTranslator DEFAULT_PERSISTENCE_EXCEPTION_TRANSLATOR = new KeyValuePersistenceExceptionTranslator();
@@ -51,6 +61,8 @@ public class KeyValueTemplate implements KeyValueOperations {
private final ConcurrentHashMap, String> keySpaceCache = new ConcurrentHashMap, String>();
private final MappingContext extends PersistentEntity, ? extends PersistentProperty>>, ? extends PersistentProperty>> mappingContext;
private final IdentifierGenerator identifierGenerator;
+ private ApplicationEventPublisher eventPublisher;
+ private final Set eventTypesToPublish = new HashSet(4);
private PersistenceExceptionTranslator exceptionTranslator = DEFAULT_PERSISTENCE_EXCEPTION_TRANSLATOR;
/**
@@ -109,22 +121,26 @@ public void insert(final Serializable id, final Object objectToInsert) {
Assert.notNull(id, "Id for object to be inserted must not be null!");
Assert.notNull(objectToInsert, "Object to be inserted must not be null!");
+ final String keyspace = resolveKeySpace(objectToInsert.getClass());
+
+ potentiallyPublishEvent(KeyValueEvent.beforeInsert(this, keyspace, id, objectToInsert));
+
execute(new KeyValueCallback() {
@Override
public Void doInKeyValue(KeyValueAdapter adapter) {
- String typeKey = resolveKeySpace(objectToInsert.getClass());
-
- if (adapter.contains(id, typeKey)) {
+ if (adapter.contains(id, keyspace)) {
throw new DuplicateKeyException(String.format(
"Cannot insert existing object with id %s!. Please use update.", id));
}
- adapter.put(id, objectToInsert, typeKey);
+ adapter.put(id, objectToInsert, keyspace);
return null;
}
});
+
+ potentiallyPublishEvent(KeyValueEvent.afterInsert(this, keyspace, id, objectToInsert));
}
/*
@@ -156,14 +172,20 @@ public void update(final Serializable id, final Object objectToUpdate) {
Assert.notNull(id, "Id for object to be inserted must not be null!");
Assert.notNull(objectToUpdate, "Object to be updated must not be null!");
+ final String keyspace = resolveKeySpace(objectToUpdate.getClass());
+
+ potentiallyPublishEvent(KeyValueEvent.beforeUpdate(this, keyspace, id, objectToUpdate));
+
execute(new KeyValueCallback() {
@Override
public Void doInKeyValue(KeyValueAdapter adapter) {
- adapter.put(id, objectToUpdate, resolveKeySpace(objectToUpdate.getClass()));
+ adapter.put(id, objectToUpdate, keyspace);
return null;
}
});
+
+ potentiallyPublishEvent(KeyValueEvent.afterUpdate(this, keyspace, id, objectToUpdate));
}
/*
@@ -209,13 +231,17 @@ public T findById(final Serializable id, final Class type) {
Assert.notNull(id, "Id for object to be inserted must not be null!");
Assert.notNull(type, "Type to fetch must not be null!");
- return execute(new KeyValueCallback() {
+ final String keyspace = resolveKeySpace(type);
+
+ potentiallyPublishEvent(KeyValueEvent.beforeGet(this, keyspace, id));
+
+ T result = execute(new KeyValueCallback() {
@SuppressWarnings("unchecked")
@Override
public T doInKeyValue(KeyValueAdapter adapter) {
- Object result = adapter.get(id, resolveKeySpace(type));
+ Object result = adapter.get(id, keyspace);
if (result == null || getKeySpace(type) == null || typeCheck(type, result)) {
return (T) result;
@@ -224,6 +250,10 @@ public T doInKeyValue(KeyValueAdapter adapter) {
return null;
}
});
+
+ potentiallyPublishEvent(KeyValueEvent.afterGet(this, keyspace, id, result));
+
+ return result;
}
/*
@@ -235,17 +265,21 @@ public void delete(final Class> type) {
Assert.notNull(type, "Type to delete must not be null!");
- final String typeKey = resolveKeySpace(type);
+ final String keyspace = resolveKeySpace(type);
+
+ potentiallyPublishEvent(KeyValueEvent.beforeDelete(this, keyspace));
execute(new KeyValueCallback() {
@Override
public Void doInKeyValue(KeyValueAdapter adapter) {
- adapter.deleteAllOf(typeKey);
+ adapter.deleteAllOf(keyspace);
return null;
}
});
+
+ potentiallyPublishEvent(KeyValueEvent.afterDelete(this, keyspace));
}
/*
@@ -272,14 +306,22 @@ public T delete(final Serializable id, final Class type) {
Assert.notNull(id, "Id for object to be inserted must not be null!");
Assert.notNull(type, "Type to delete must not be null!");
- return execute(new KeyValueCallback() {
+ final String keyspace = resolveKeySpace(type);
+
+ potentiallyPublishEvent(KeyValueEvent.beforeDelete(this, keyspace, id));
+
+ T result = execute(new KeyValueCallback() {
@SuppressWarnings("unchecked")
@Override
public T doInKeyValue(KeyValueAdapter adapter) {
- return (T) adapter.delete(id, resolveKeySpace(type));
+ return (T) adapter.delete(id, keyspace);
}
});
+
+ potentiallyPublishEvent(KeyValueEvent.afterDelete(this, keyspace, id, result));
+
+ return result;
}
/*
@@ -416,14 +458,37 @@ public void setExceptionTranslator(PersistenceExceptionTranslator exceptionTrans
this.exceptionTranslator = exceptionTranslator;
}
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
+ */
+ @Override
+ public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+ eventPublisher = applicationContext;
+ }
+
+ /**
+ * Define the event types to publish via {@link ApplicationEventPublisher}.
+ *
+ * @param eventTypesToPublish use {@literal null} or {@link Collections#emptySet()} to disable publishing.
+ */
+ public void setEventTypesToPublish(Set eventTypesToPublish) {
+
+ this.eventTypesToPublish.clear();
+
+ if (!CollectionUtils.isEmpty(eventTypesToPublish)) {
+ this.eventTypesToPublish.addAll(eventTypesToPublish);
+ }
+ }
+
protected String resolveKeySpace(Class> type) {
Class> userClass = ClassUtils.getUserClass(type);
- String potentialAlias = keySpaceCache.get(userClass);
+ String potentialKeySpace = keySpaceCache.get(userClass);
- if (potentialAlias != null) {
- return potentialAlias;
+ if (potentialKeySpace != null) {
+ return potentialKeySpace;
}
String keySpaceString = null;
@@ -450,4 +515,15 @@ private RuntimeException resolveExceptionIfPossible(RuntimeException e) {
DataAccessException translatedException = exceptionTranslator.translateExceptionIfPossible(e);
return translatedException != null ? translatedException : e;
}
+
+ private void potentiallyPublishEvent(KeyValueEvent event) {
+
+ if (eventPublisher == null) {
+ return;
+ }
+
+ if (eventTypesToPublish.contains(event.getType()) || eventTypesToPublish.contains(KeyValueEvent.Type.ANY)) {
+ eventPublisher.publishEvent(event);
+ }
+ }
}
diff --git a/src/main/java/org/springframework/data/keyvalue/core/event/KeyValueEvent.java b/src/main/java/org/springframework/data/keyvalue/core/event/KeyValueEvent.java
new file mode 100644
index 00000000..0dbeb837
--- /dev/null
+++ b/src/main/java/org/springframework/data/keyvalue/core/event/KeyValueEvent.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.data.keyvalue.core.event;
+
+import java.io.Serializable;
+
+import org.springframework.context.ApplicationEvent;
+
+/**
+ * {@link KeyValueEvent} gets published for operations executed by eg.
+ * {@link org.springframework.data.keyvalue.core.KeyValueTemplate}. Use the {@link #getType()} to determine which event
+ * has been emitted.
+ *
+ * @author Christoph Strobl
+ * @author Thomas Darimont
+ * @param
+ */
+public class KeyValueEvent extends ApplicationEvent {
+
+ private static final long serialVersionUID = -7128527253428193044L;
+
+ public enum Type {
+ ANY, BEFORE_INSERT, AFTER_INSERT, BEFORE_UPDATE, AFTER_UPDATE, BEFORE_DELETE, AFTER_DELETE, BEFORE_GET, AFTER_GET
+ }
+
+ private final Type type;
+ private final String keyspace;
+ private final Serializable id;
+ private final Object value;
+
+ protected KeyValueEvent(Object source, Type type, String keyspace, Serializable id, Object value) {
+
+ super(source);
+ this.type = type;
+ this.keyspace = keyspace;
+ this.id = id;
+ this.value = value;
+ }
+
+ /**
+ * @return {@link Type} of event. Never {@literal null}.
+ */
+ public Type getType() {
+ return type;
+ }
+
+ /**
+ * @return affected keyspace. Never {@literal null}.
+ */
+ public String getKeyspace() {
+ return keyspace;
+ }
+
+ /**
+ * @return can be {@literal null}.
+ */
+ public Serializable getId() {
+ return id;
+ }
+
+ /**
+ * @return can be {@literal null}.
+ */
+ public Object getValue() {
+ return value;
+ }
+
+ @Override
+ public String toString() {
+ return "KeyValueEvent [type=" + type + ", keyspace=" + keyspace + ", id=" + id + "]";
+ }
+
+ public static GetEvent beforeGet(Object source, String keyspace, Serializable id) {
+ return new GetEvent(source, Type.BEFORE_GET, keyspace, id, null);
+ }
+
+ public static GetEvent afterGet(Object source, String keyspace, Serializable id, Object value) {
+ return new GetEvent(source, Type.AFTER_GET, keyspace, id, value);
+ }
+
+ public static InsertEvent beforeInsert(Object source, String keyspace, Serializable id, Object value) {
+ return new InsertEvent(source, Type.BEFORE_INSERT, keyspace, id, value);
+ }
+
+ public static InsertEvent afterInsert(Object source, String keyspace, Serializable id, Object value) {
+ return new InsertEvent(source, Type.AFTER_INSERT, keyspace, id, value);
+ }
+
+ public static UpdateEvent beforeUpdate(Object source, String keyspace, Serializable id, Object value) {
+ return new UpdateEvent(source, Type.BEFORE_UPDATE, keyspace, id, value);
+ }
+
+ public static UpdateEvent afterUpdate(Object source, String keyspace, Serializable id, Object value) {
+ return new UpdateEvent(source, Type.AFTER_UPDATE, keyspace, id, value);
+ }
+
+ public static DropKeyspaceEvent beforeDelete(Object source, String keyspace) {
+ return new DropKeyspaceEvent(source, Type.BEFORE_DELETE, keyspace);
+ }
+
+ public static DeleteEvent beforeDelete(Object source, String keyspace, Serializable id) {
+ return beforeDelete(source, keyspace, id, null);
+ }
+
+ public static DeleteEvent beforeDelete(Object source, String keyspace, Serializable id, Object value) {
+ return new DeleteEvent(source, Type.BEFORE_DELETE, keyspace, id, value);
+ }
+
+ public static DropKeyspaceEvent afterDelete(Object source, String keyspace) {
+ return new DropKeyspaceEvent(source, Type.AFTER_DELETE, keyspace);
+ }
+
+ public static DeleteEvent afterDelete(Object source, String keyspace, Serializable id, Object value) {
+ return new DeleteEvent(source, Type.AFTER_DELETE, keyspace, id, value);
+ }
+
+ public static class InsertEvent extends KeyValueEvent {
+
+ private static final long serialVersionUID = -1;
+
+ InsertEvent(Object source, Type type, String keyspace, Serializable id, Object value) {
+ super(source, type, keyspace, id, value);
+ }
+ }
+
+ public static class UpdateEvent extends KeyValueEvent {
+
+ private static final long serialVersionUID = -1;
+
+ UpdateEvent(Object source, Type type, String keyspace, Serializable id, Object value) {
+ super(source, type, keyspace, id, value);
+ }
+ }
+
+ public static class DeleteEvent extends KeyValueEvent {
+
+ private static final long serialVersionUID = -1;
+
+ DeleteEvent(Object source, Type type, String keyspace, Serializable id, Object value) {
+ super(source, type, keyspace, id, value);
+ }
+ }
+
+ public static class DropKeyspaceEvent extends DeleteEvent {
+
+ private static final long serialVersionUID = -1;
+
+ DropKeyspaceEvent(Object source, Type type, String keyspace) {
+ super(source, type, keyspace, null, null);
+ }
+ }
+
+ public static class GetEvent extends KeyValueEvent {
+
+ private static final long serialVersionUID = -1;
+
+ protected GetEvent(Object source, Type type, String keyspace,
+ Serializable id, Object value) {
+ super(source, type, keyspace, id, value);
+ }
+
+ }
+
+}
diff --git a/src/main/java/org/springframework/data/map/MapKeyValueAdapter.java b/src/main/java/org/springframework/data/map/MapKeyValueAdapter.java
index dbe9719f..93c946e5 100644
--- a/src/main/java/org/springframework/data/map/MapKeyValueAdapter.java
+++ b/src/main/java/org/springframework/data/map/MapKeyValueAdapter.java
@@ -142,6 +142,17 @@ public void deleteAllOf(Serializable keyspace) {
getKeySpaceMap(keyspace).clear();
}
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.keyvalue.core.KeyValueAdapter#hasKeyspace(java.io.Serializable)
+ */
+ @Override
+ public boolean hasKeyspace(Serializable keyspace) {
+
+ Assert.notNull(keyspace, "Collection must not be null for lookup.");
+ return store.containsKey(keyspace);
+ }
+
/*
* (non-Javadoc)
* @see org.springframework.data.keyvalue.core.KeyValueAdapter#clear()
diff --git a/src/test/java/org/springframework/data/keyvalue/core/KeyValueTemplateUnitTests.java b/src/test/java/org/springframework/data/keyvalue/core/KeyValueTemplateUnitTests.java
index d2071471..5402f860 100644
--- a/src/test/java/org/springframework/data/keyvalue/core/KeyValueTemplateUnitTests.java
+++ b/src/test/java/org/springframework/data/keyvalue/core/KeyValueTemplateUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014 the original author or authors.
+ * Copyright 2014-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,6 +28,7 @@
import java.lang.annotation.Target;
import java.util.Arrays;
import java.util.Collection;
+import java.util.HashSet;
import org.junit.Before;
import org.junit.Rule;
@@ -37,17 +38,26 @@
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
+import org.springframework.context.ApplicationContext;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Persistent;
import org.springframework.data.annotation.TypeAlias;
import org.springframework.data.keyvalue.annotation.KeySpace;
+import org.springframework.data.keyvalue.core.event.KeyValueEvent;
+import org.springframework.data.keyvalue.core.event.KeyValueEvent.DeleteEvent;
+import org.springframework.data.keyvalue.core.event.KeyValueEvent.DropKeyspaceEvent;
+import org.springframework.data.keyvalue.core.event.KeyValueEvent.GetEvent;
+import org.springframework.data.keyvalue.core.event.KeyValueEvent.InsertEvent;
+import org.springframework.data.keyvalue.core.event.KeyValueEvent.Type;
+import org.springframework.data.keyvalue.core.event.KeyValueEvent.UpdateEvent;
import org.springframework.data.keyvalue.core.query.KeyValueQuery;
import org.springframework.util.ObjectUtils;
/**
* @author Christoph Strobl
+ * @author Thomas Darimont
*/
@RunWith(MockitoJUnitRunner.class)
public class KeyValueTemplateUnitTests {
@@ -63,10 +73,12 @@ public class KeyValueTemplateUnitTests {
private @Mock KeyValueAdapter adapterMock;
private KeyValueTemplate template;
+ private @Mock ApplicationContext ctxMock;
@Before
public void setUp() throws InstantiationException, IllegalAccessException {
this.template = new KeyValueTemplate(adapterMock);
+ this.template.setApplicationContext(ctxMock);
}
/**
@@ -420,6 +432,225 @@ public void setttingNullPersistenceExceptionTranslatorShouldThrowException() {
template.setExceptionTranslator(null);
}
+ /**
+ * @see DATAKV-91
+ */
+ @Test
+ public void shouldNotPublishEventWhenNoApplicationContextSet() {
+
+ template.setApplicationContext(null);
+ template.setEventTypesToPublish(new HashSet(Arrays.asList(KeyValueEvent.Type.AFTER_DELETE,
+ KeyValueEvent.Type.AFTER_INSERT, KeyValueEvent.Type.AFTER_UPDATE, KeyValueEvent.Type.BEFORE_DELETE,
+ KeyValueEvent.Type.BEFORE_INSERT, KeyValueEvent.Type.BEFORE_UPDATE)));
+
+ template.insert("1", FOO_ONE);
+
+ verifyZeroInteractions(ctxMock);
+ }
+
+ /**
+ * @see DATAKV-91
+ */
+ @Test
+ public void shouldNotPublishEventWhenNotExplicitlySetForPublication() {
+
+ template.setEventTypesToPublish(new HashSet(Arrays.asList(KeyValueEvent.Type.AFTER_DELETE)));
+
+ template.insert("1", FOO_ONE);
+
+ verifyZeroInteractions(ctxMock);
+ }
+
+ /**
+ * @see DATAKV-91
+ */
+ @Test
+ public void shouldPublishBeforeInsertEventCorrectly() {
+
+ template.setEventTypesToPublish(new HashSet(Arrays.asList(KeyValueEvent.Type.BEFORE_INSERT)));
+
+ template.insert("1", FOO_ONE);
+
+ ArgumentCaptor captor = ArgumentCaptor.forClass(InsertEvent.class);
+
+ verify(ctxMock, times(1)).publishEvent(captor.capture());
+ verifyNoMoreInteractions(ctxMock);
+
+ assertThat(captor.getValue().getType(), is(Type.BEFORE_INSERT));
+ assertThat(captor.getValue().getId(), is((Serializable) "1"));
+ assertThat(captor.getValue().getKeyspace(), is(Foo.class.getName()));
+ assertThat(captor.getValue().getValue(), is((Object) FOO_ONE));
+ }
+
+ /**
+ * @see DATAKV-91
+ */
+ @Test
+ public void shouldPublishAfterInsertEventCorrectly() {
+
+ template.setEventTypesToPublish(new HashSet(Arrays.asList(KeyValueEvent.Type.AFTER_INSERT)));
+
+ template.insert("1", FOO_ONE);
+
+ ArgumentCaptor captor = ArgumentCaptor.forClass(InsertEvent.class);
+
+ verify(ctxMock, times(1)).publishEvent(captor.capture());
+ verifyNoMoreInteractions(ctxMock);
+
+ assertThat(captor.getValue().getType(), is(Type.AFTER_INSERT));
+ assertThat(captor.getValue().getId(), is((Serializable) "1"));
+ assertThat(captor.getValue().getKeyspace(), is(Foo.class.getName()));
+ assertThat(captor.getValue().getValue(), is((Object) FOO_ONE));
+ }
+
+ /**
+ * @see DATAKV-91
+ */
+ @Test
+ public void shouldPublishBeforeUpdateEventCorrectly() {
+
+ template.setEventTypesToPublish(new HashSet(Arrays.asList(KeyValueEvent.Type.BEFORE_UPDATE)));
+
+ template.update("1", FOO_ONE);
+
+ ArgumentCaptor captor = ArgumentCaptor.forClass(UpdateEvent.class);
+
+ verify(ctxMock, times(1)).publishEvent(captor.capture());
+ verifyNoMoreInteractions(ctxMock);
+
+ assertThat(captor.getValue().getType(), is(Type.BEFORE_UPDATE));
+ assertThat(captor.getValue().getId(), is((Serializable) "1"));
+ assertThat(captor.getValue().getKeyspace(), is(Foo.class.getName()));
+ assertThat(captor.getValue().getValue(), is((Object) FOO_ONE));
+ }
+
+ /**
+ * @see DATAKV-91
+ */
+ @Test
+ public void shouldPublishAfterUpdateEventCorrectly() {
+
+ template.setEventTypesToPublish(new HashSet(Arrays.asList(KeyValueEvent.Type.AFTER_UPDATE)));
+
+ template.update("1", FOO_ONE);
+
+ ArgumentCaptor captor = ArgumentCaptor.forClass(UpdateEvent.class);
+
+ verify(ctxMock, times(1)).publishEvent(captor.capture());
+ verifyNoMoreInteractions(ctxMock);
+
+ assertThat(captor.getValue().getType(), is(Type.AFTER_UPDATE));
+ assertThat(captor.getValue().getId(), is((Serializable) "1"));
+ assertThat(captor.getValue().getKeyspace(), is(Foo.class.getName()));
+ assertThat(captor.getValue().getValue(), is((Object) FOO_ONE));
+ }
+
+ /**
+ * @see DATAKV-91
+ */
+ @Test
+ public void shouldPublishBeforeDeleteEventCorrectly() {
+
+ template.setEventTypesToPublish(new HashSet(Arrays.asList(KeyValueEvent.Type.BEFORE_DELETE)));
+
+ template.delete("1", FOO_ONE.getClass());
+
+ ArgumentCaptor captor = ArgumentCaptor.forClass(DeleteEvent.class);
+
+ verify(ctxMock, times(1)).publishEvent(captor.capture());
+ verifyNoMoreInteractions(ctxMock);
+
+ assertThat(captor.getValue().getType(), is(Type.BEFORE_DELETE));
+ assertThat(captor.getValue().getId(), is((Serializable) "1"));
+ assertThat(captor.getValue().getKeyspace(), is(Foo.class.getName()));
+ assertThat(captor.getValue().getValue(), nullValue());
+ }
+
+ /**
+ * @see DATAKV-91
+ */
+ @Test
+ public void shouldPublishAfterDeleteEventCorrectly() {
+
+ template.setEventTypesToPublish(new HashSet(Arrays.asList(KeyValueEvent.Type.AFTER_DELETE)));
+ when(adapterMock.delete(eq("1"), eq(FOO_ONE.getClass().getName()))).thenReturn(FOO_ONE);
+
+ template.delete("1", FOO_ONE.getClass());
+
+ ArgumentCaptor captor = ArgumentCaptor.forClass(DeleteEvent.class);
+
+ verify(ctxMock, times(1)).publishEvent(captor.capture());
+ verifyNoMoreInteractions(ctxMock);
+
+ assertThat(captor.getValue().getType(), is(Type.AFTER_DELETE));
+ assertThat(captor.getValue().getId(), is((Serializable) "1"));
+ assertThat(captor.getValue().getKeyspace(), is(Foo.class.getName()));
+ assertThat(captor.getValue().getValue(), is((Object) FOO_ONE));
+ }
+
+ /**
+ * @see DATAKV-91
+ */
+ @Test
+ public void shouldPublishBeforeGetEventCorrectly() {
+
+ template.setEventTypesToPublish(new HashSet(Arrays.asList(KeyValueEvent.Type.BEFORE_GET)));
+ when(adapterMock.get(eq("1"), eq(FOO_ONE.getClass().getName()))).thenReturn(FOO_ONE);
+
+ template.findById("1", FOO_ONE.getClass());
+
+ ArgumentCaptor captor = ArgumentCaptor.forClass(GetEvent.class);
+
+ verify(ctxMock, times(1)).publishEvent(captor.capture());
+ verifyNoMoreInteractions(ctxMock);
+
+ assertThat(captor.getValue().getType(), is(Type.BEFORE_GET));
+ assertThat(captor.getValue().getId(), is((Serializable) "1"));
+ assertThat(captor.getValue().getKeyspace(), is(Foo.class.getName()));
+ assertThat(captor.getValue().getValue(), nullValue());
+ }
+
+ /**
+ * @see DATAKV-91
+ */
+ @Test
+ public void shouldPublishAfterGetEventCorrectly() {
+
+ template.setEventTypesToPublish(new HashSet(Arrays.asList(KeyValueEvent.Type.AFTER_GET)));
+ when(adapterMock.get(eq("1"), eq(FOO_ONE.getClass().getName()))).thenReturn(FOO_ONE);
+
+ template.findById("1", FOO_ONE.getClass());
+
+ ArgumentCaptor captor = ArgumentCaptor.forClass(GetEvent.class);
+
+ verify(ctxMock, times(1)).publishEvent(captor.capture());
+ verifyNoMoreInteractions(ctxMock);
+
+ assertThat(captor.getValue().getType(), is(Type.AFTER_GET));
+ assertThat(captor.getValue().getId(), is((Serializable) "1"));
+ assertThat(captor.getValue().getKeyspace(), is(Foo.class.getName()));
+ assertThat(captor.getValue().getValue(), is((Object) FOO_ONE));
+ }
+
+ /**
+ * @see DATAKV-91
+ */
+ @Test
+ public void shouldPublishDropKeyspaceEventCorrectly() {
+
+ template.setEventTypesToPublish(new HashSet(Arrays.asList(KeyValueEvent.Type.AFTER_DELETE)));
+
+ template.delete(FOO_ONE.getClass());
+
+ ArgumentCaptor captor = ArgumentCaptor.forClass(DropKeyspaceEvent.class);
+
+ verify(ctxMock, times(1)).publishEvent(captor.capture());
+ verifyNoMoreInteractions(ctxMock);
+
+ assertThat(captor.getValue().getType(), is(Type.AFTER_DELETE));
+ assertThat(captor.getValue().getKeyspace(), is(Foo.class.getName()));
+ }
+
static class Foo {
String foo;