DATAKV-91 - Add support for sending application events.

We now allow definition of event types to be published via the application context.

Original pull request: #5.
This commit is contained in:
Christoph Strobl
2015-04-13 12:12:56 +02:00
committed by Thomas Darimont
parent a8a37d4a32
commit 07b3a1547c
5 changed files with 521 additions and 18 deletions

View File

@@ -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);
}

View File

@@ -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 static org.springframework.data.keyvalue.core.KeySpaceUtils.*;
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.PersistentProperty;
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 @@ import org.springframework.util.StringUtils;
*
* @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<Class<?>, String> keySpaceCache = new ConcurrentHashMap<Class<?>, String>();
private final MappingContext<? extends PersistentEntity<?, ? extends PersistentProperty<?>>, ? extends PersistentProperty<?>> mappingContext;
private final IdentifierGenerator identifierGenerator;
private ApplicationEventPublisher eventPublisher;
private final Set<KeyValueEvent.Type> eventTypesToPublish = new HashSet<KeyValueEvent.Type>(4);
private PersistenceExceptionTranslator exceptionTranslator = DEFAULT_PERSISTENCE_EXCEPTION_TRANSLATOR;
/**
@@ -109,22 +121,26 @@ public class KeyValueTemplate implements KeyValueOperations {
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<Void>() {
@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 class KeyValueTemplate implements KeyValueOperations {
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<Void>() {
@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 class KeyValueTemplate implements KeyValueOperations {
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<T>() {
final String keyspace = resolveKeySpace(type);
potentiallyPublishEvent(KeyValueEvent.beforeGet(this, keyspace, id));
T result = execute(new KeyValueCallback<T>() {
@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 class KeyValueTemplate implements KeyValueOperations {
return null;
}
});
potentiallyPublishEvent(KeyValueEvent.afterGet(this, keyspace, id, result));
return result;
}
/*
@@ -235,17 +265,21 @@ public class KeyValueTemplate implements KeyValueOperations {
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<Void>() {
@Override
public Void doInKeyValue(KeyValueAdapter adapter) {
adapter.deleteAllOf(typeKey);
adapter.deleteAllOf(keyspace);
return null;
}
});
potentiallyPublishEvent(KeyValueEvent.afterDelete(this, keyspace));
}
/*
@@ -272,14 +306,22 @@ public class KeyValueTemplate implements KeyValueOperations {
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<T>() {
final String keyspace = resolveKeySpace(type);
potentiallyPublishEvent(KeyValueEvent.beforeDelete(this, keyspace, id));
T result = execute(new KeyValueCallback<T>() {
@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 class KeyValueTemplate implements KeyValueOperations {
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<KeyValueEvent.Type> 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 @@ public class KeyValueTemplate implements KeyValueOperations {
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);
}
}
}

View File

@@ -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 <T>
*/
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);
}
}
}

View File

@@ -142,6 +142,17 @@ public class MapKeyValueAdapter extends AbstractKeyValueAdapter {
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()

View File

@@ -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.RetentionPolicy;
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.junit.runner.RunWith;
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 class KeyValueTemplateUnitTests {
template.setExceptionTranslator(null);
}
/**
* @see DATAKV-91
*/
@Test
public void shouldNotPublishEventWhenNoApplicationContextSet() {
template.setApplicationContext(null);
template.setEventTypesToPublish(new HashSet<KeyValueEvent.Type>(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<KeyValueEvent.Type>(Arrays.asList(KeyValueEvent.Type.AFTER_DELETE)));
template.insert("1", FOO_ONE);
verifyZeroInteractions(ctxMock);
}
/**
* @see DATAKV-91
*/
@Test
public void shouldPublishBeforeInsertEventCorrectly() {
template.setEventTypesToPublish(new HashSet<KeyValueEvent.Type>(Arrays.asList(KeyValueEvent.Type.BEFORE_INSERT)));
template.insert("1", FOO_ONE);
ArgumentCaptor<InsertEvent> 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<KeyValueEvent.Type>(Arrays.asList(KeyValueEvent.Type.AFTER_INSERT)));
template.insert("1", FOO_ONE);
ArgumentCaptor<InsertEvent> 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<KeyValueEvent.Type>(Arrays.asList(KeyValueEvent.Type.BEFORE_UPDATE)));
template.update("1", FOO_ONE);
ArgumentCaptor<UpdateEvent> 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<KeyValueEvent.Type>(Arrays.asList(KeyValueEvent.Type.AFTER_UPDATE)));
template.update("1", FOO_ONE);
ArgumentCaptor<UpdateEvent> 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<KeyValueEvent.Type>(Arrays.asList(KeyValueEvent.Type.BEFORE_DELETE)));
template.delete("1", FOO_ONE.getClass());
ArgumentCaptor<DeleteEvent> 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<KeyValueEvent.Type>(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<DeleteEvent> 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<KeyValueEvent.Type>(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<GetEvent> 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<KeyValueEvent.Type>(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<GetEvent> 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<KeyValueEvent.Type>(Arrays.asList(KeyValueEvent.Type.AFTER_DELETE)));
template.delete(FOO_ONE.getClass());
ArgumentCaptor<DropKeyspaceEvent> 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;