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 b7fe642..38ed642 100644 --- a/src/main/java/org/springframework/data/keyvalue/core/KeyValueTemplate.java +++ b/src/main/java/org/springframework/data/keyvalue/core/KeyValueTemplate.java @@ -22,10 +22,8 @@ import java.util.HashSet; import java.util.List; import java.util.Set; -import org.springframework.beans.BeansException; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.ApplicationEventPublisherAware; import org.springframework.dao.DataAccessException; import org.springframework.dao.DuplicateKeyException; import org.springframework.dao.InvalidDataAccessApiUsageException; @@ -50,17 +48,18 @@ import org.springframework.util.CollectionUtils; * @author Oliver Gierke * @author Thomas Darimont */ -public class KeyValueTemplate implements KeyValueOperations, ApplicationContextAware { +public class KeyValueTemplate implements KeyValueOperations, ApplicationEventPublisherAware { private static final PersistenceExceptionTranslator DEFAULT_PERSISTENCE_EXCEPTION_TRANSLATOR = new KeyValuePersistenceExceptionTranslator(); private final KeyValueAdapter adapter; private final MappingContext, ? extends KeyValuePersistentProperty> mappingContext; private final IdentifierGenerator identifierGenerator; - private final Set eventTypesToPublish = new HashSet(4); + private ApplicationEventPublisher eventPublisher; + private boolean publishEvents = true; + private final Set> eventTypesToPublish = new HashSet>(0); private PersistenceExceptionTranslator exceptionTranslator = DEFAULT_PERSISTENCE_EXCEPTION_TRANSLATOR; - private ApplicationEventPublisher eventPublisher; /** * Create new {@link KeyValueTemplate} using the given {@link KeyValueAdapter} with a default @@ -118,7 +117,7 @@ public class KeyValueTemplate implements KeyValueOperations, ApplicationContextA final String keyspace = resolveKeySpace(objectToInsert.getClass()); - potentiallyPublishEvent(KeyValueEvent.beforeInsert(this, keyspace, id, objectToInsert)); + potentiallyPublishEvent(KeyValueEvent.beforeInsert(id, keyspace, objectToInsert.getClass(), objectToInsert)); execute(new KeyValueCallback() { @@ -135,7 +134,7 @@ public class KeyValueTemplate implements KeyValueOperations, ApplicationContextA } }); - potentiallyPublishEvent(KeyValueEvent.afterInsert(this, keyspace, id, objectToInsert)); + potentiallyPublishEvent(KeyValueEvent.afterInsert(id, keyspace, objectToInsert.getClass(), objectToInsert)); } /* @@ -169,18 +168,18 @@ public class KeyValueTemplate implements KeyValueOperations, ApplicationContextA final String keyspace = resolveKeySpace(objectToUpdate.getClass()); - potentiallyPublishEvent(KeyValueEvent.beforeUpdate(this, keyspace, id, objectToUpdate)); + potentiallyPublishEvent(KeyValueEvent.beforeUpdate(id, keyspace, objectToUpdate.getClass(), objectToUpdate)); - execute(new KeyValueCallback() { + Object existing = execute(new KeyValueCallback() { @Override - public Void doInKeyValue(KeyValueAdapter adapter) { - adapter.put(id, objectToUpdate, keyspace); - return null; + public Object doInKeyValue(KeyValueAdapter adapter) { + return adapter.put(id, objectToUpdate, keyspace); } }); - potentiallyPublishEvent(KeyValueEvent.afterUpdate(this, keyspace, id, objectToUpdate)); + potentiallyPublishEvent(KeyValueEvent + .afterUpdate(id, keyspace, objectToUpdate.getClass(), objectToUpdate, existing)); } /* @@ -228,7 +227,7 @@ public class KeyValueTemplate implements KeyValueOperations, ApplicationContextA final String keyspace = resolveKeySpace(type); - potentiallyPublishEvent(KeyValueEvent.beforeGet(this, keyspace, id)); + potentiallyPublishEvent(KeyValueEvent.beforeGet(id, keyspace, type)); T result = execute(new KeyValueCallback() { @@ -246,7 +245,7 @@ public class KeyValueTemplate implements KeyValueOperations, ApplicationContextA } }); - potentiallyPublishEvent(KeyValueEvent.afterGet(this, keyspace, id, result)); + potentiallyPublishEvent(KeyValueEvent.afterGet(id, keyspace, type, result)); return result; } @@ -262,7 +261,7 @@ public class KeyValueTemplate implements KeyValueOperations, ApplicationContextA final String keyspace = resolveKeySpace(type); - potentiallyPublishEvent(KeyValueEvent.beforeDelete(this, keyspace)); + potentiallyPublishEvent(KeyValueEvent.beforeDropKeySpace(keyspace, type)); execute(new KeyValueCallback() { @@ -274,7 +273,7 @@ public class KeyValueTemplate implements KeyValueOperations, ApplicationContextA } }); - potentiallyPublishEvent(KeyValueEvent.afterDelete(this, keyspace)); + potentiallyPublishEvent(KeyValueEvent.afterDropKeySpace(keyspace, type)); } /* @@ -298,12 +297,12 @@ public class KeyValueTemplate implements KeyValueOperations, ApplicationContextA @Override public T delete(final Serializable id, final Class type) { - Assert.notNull(id, "Id for object to be inserted must not be null!"); + Assert.notNull(id, "Id for object to be deleted must not be null!"); Assert.notNull(type, "Type to delete must not be null!"); final String keyspace = resolveKeySpace(type); - potentiallyPublishEvent(KeyValueEvent.beforeDelete(this, keyspace, id)); + potentiallyPublishEvent(KeyValueEvent.beforeDelete(id, keyspace, type)); T result = execute(new KeyValueCallback() { @@ -314,7 +313,7 @@ public class KeyValueTemplate implements KeyValueOperations, ApplicationContextA } }); - potentiallyPublishEvent(KeyValueEvent.afterDelete(this, keyspace, id, result)); + potentiallyPublishEvent(KeyValueEvent.afterDelete(id, keyspace, type, result)); return result; } @@ -454,24 +453,28 @@ public class KeyValueTemplate implements KeyValueOperations, ApplicationContextA /* * (non-Javadoc) - * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext) + * @see org.springframework.context.ApplicationEventPublisherAware#setApplicationEventPublisher(org.springframework.context.ApplicationEventPublisher) */ @Override - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - eventPublisher = applicationContext; + public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { + this.eventPublisher = applicationEventPublisher; } /** * Define the event types to publish via {@link ApplicationEventPublisher}. * - * @param eventTypesToPublish use {@literal null} or {@link Collections#emptySet()} to disable publishing. + * @param eventTypesToPublish use {@literal null} or {@link Collections#emptySet()} to stop publishing. */ - public void setEventTypesToPublish(Set eventTypesToPublish) { + public void setEventTypesToPublish(Set> eventTypesToPublish) { this.eventTypesToPublish.clear(); if (!CollectionUtils.isEmpty(eventTypesToPublish)) { + + this.publishEvents = true; this.eventTypesToPublish.addAll(eventTypesToPublish); + } else { + this.publishEvents = false; } } @@ -495,7 +498,7 @@ public class KeyValueTemplate implements KeyValueOperations, ApplicationContextA return; } - if (eventTypesToPublish.contains(event.getType()) || eventTypesToPublish.contains(KeyValueEvent.Type.ANY)) { + if (publishEvents && (eventTypesToPublish.isEmpty() || eventTypesToPublish.contains(event.getClass()))) { 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 index 0dbeb83..6587c71 100644 --- a/src/main/java/org/springframework/data/keyvalue/core/event/KeyValueEvent.java +++ b/src/main/java/org/springframework/data/keyvalue/core/event/KeyValueEvent.java @@ -28,33 +28,16 @@ import org.springframework.context.ApplicationEvent; * @author Thomas Darimont * @param */ -public class KeyValueEvent extends ApplicationEvent { +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) { - + protected KeyValueEvent(Object source, String keyspace) { + 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; } /** @@ -64,114 +47,374 @@ public class KeyValueEvent extends ApplicationEvent { 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 + "]"; + return "KeyValueEvent [keyspace=" + keyspace + ", source=" + getSource() + "]"; } - public static GetEvent beforeGet(Object source, String keyspace, Serializable id) { - return new GetEvent(source, Type.BEFORE_GET, keyspace, id, null); + /** + * Create new {@link BeforeGetEvent}. + * + * @param id + * @param keySpace + * @param type + * @return + */ + public static BeforeGetEvent beforeGet(Serializable id, String keySpace, Class type) { + return new BeforeGetEvent(id, keySpace, type); } - public static GetEvent afterGet(Object source, String keyspace, Serializable id, Object value) { - return new GetEvent(source, Type.AFTER_GET, keyspace, id, value); + /** + * Create new {@link AfterGetEvent}. + * + * @param id + * @param keySpace + * @param type + * @param value + * @return + */ + public static AfterGetEvent afterGet(Serializable id, String keySpace, Class type, T value) { + return new AfterGetEvent(id, keySpace, type, value); } - public static InsertEvent beforeInsert(Object source, String keyspace, Serializable id, Object value) { - return new InsertEvent(source, Type.BEFORE_INSERT, keyspace, id, value); + /** + * Create new {@link BeforeInsertEvent}. + * + * @param id + * @param keySpace + * @param type + * @param value + * @return + */ + public static BeforeInsertEvent beforeInsert(Serializable id, String keySpace, Class type, T value) { + return new BeforeInsertEvent(id, keySpace, type, value); } - public static InsertEvent afterInsert(Object source, String keyspace, Serializable id, Object value) { - return new InsertEvent(source, Type.AFTER_INSERT, keyspace, id, value); + /** + * Create new {@link AfterInsertEvent}. + * + * @param id + * @param keySpace + * @param type + * @param value + * @return + */ + public static AfterInsertEvent afterInsert(Serializable id, String keySpace, Class type, T value) { + return new AfterInsertEvent(id, keySpace, type, value); } - public static UpdateEvent beforeUpdate(Object source, String keyspace, Serializable id, Object value) { - return new UpdateEvent(source, Type.BEFORE_UPDATE, keyspace, id, value); + /** + * Create new {@link BeforeUpdateEvent}. + * + * @param id + * @param keySpace + * @param type + * @param value + * @return + */ + public static BeforeUpdateEvent beforeUpdate(Serializable id, String keySpace, Class type, T value) { + return new BeforeUpdateEvent(id, keySpace, type, value); } - public static UpdateEvent afterUpdate(Object source, String keyspace, Serializable id, Object value) { - return new UpdateEvent(source, Type.AFTER_UPDATE, keyspace, id, value); + /** + * Create new {@link AfterUpdateEvent}. + * + * @param id + * @param keySpace + * @param type + * @param actualValue + * @param previousValue + * @return + */ + public static AfterUpdateEvent afterUpdate(Serializable id, String keySpace, Class type, + T actualValue, Object previousValue) { + return new AfterUpdateEvent(id, keySpace, type, actualValue, previousValue); } - public static DropKeyspaceEvent beforeDelete(Object source, String keyspace) { - return new DropKeyspaceEvent(source, Type.BEFORE_DELETE, keyspace); + /** + * Create new {@link BeforeDropKeySpaceEvent}. + * + * @param keySpace + * @param type + * @return + */ + public static BeforeDropKeySpaceEvent beforeDropKeySpace(String keySpace, Class type) { + return new BeforeDropKeySpaceEvent(keySpace, type); } - public static DeleteEvent beforeDelete(Object source, String keyspace, Serializable id) { - return beforeDelete(source, keyspace, id, null); + /** + * Create new {@link AfterDropKeySpaceEvent}. + * + * @param keySpace + * @param type + * @return + */ + public static AfterDropKeySpaceEvent afterDropKeySpace(String keySpace, Class type) { + return new AfterDropKeySpaceEvent(keySpace, type); } - public static DeleteEvent beforeDelete(Object source, String keyspace, Serializable id, Object value) { - return new DeleteEvent(source, Type.BEFORE_DELETE, keyspace, id, value); + /** + * Create new {@link BeforeDeleteEvent}. + * + * @param id + * @param keySpace + * @param type + * @return + */ + public static BeforeDeleteEvent beforeDelete(Serializable id, String keySpace, Class type) { + return new BeforeDeleteEvent(id, keySpace, type); } - public static DropKeyspaceEvent afterDelete(Object source, String keyspace) { - return new DropKeyspaceEvent(source, Type.AFTER_DELETE, keyspace); + /** + * Create new {@link AfterDeleteEvent}. + * + * @param id + * @param keySpace + * @param type + * @param value + * @return + */ + public static AfterDeleteEvent afterDelete(Serializable id, String keySpace, Class type, T value) { + return new AfterDeleteEvent(id, keySpace, type, value); } - public static DeleteEvent afterDelete(Object source, String keyspace, Serializable id, Object value) { - return new DeleteEvent(source, Type.AFTER_DELETE, keyspace, id, value); - } + /** + * @author Christoph Strobl + * @param + */ + @SuppressWarnings("serial") + abstract static class KeyBasedEvent extends KeyValueEvent { - public static class InsertEvent extends KeyValueEvent { + private Serializable key; + private Class type; - private static final long serialVersionUID = -1; + protected KeyBasedEvent(Serializable key, String keySpace, Class type) { - InsertEvent(Object source, Type type, String keyspace, Serializable id, Object value) { - super(source, type, keyspace, id, value); + super(type, keySpace); + this.key = key; + } + + public Serializable getKey() { + return key; + } + + /* + * (non-Javadoc) + * @see java.util.EventObject#getSource() + */ + @Override + public Serializable getSource() { + return getKey(); + } + + /** + * Get the type of the element the {@link KeyValueEvent} refers to. + * + * @return + */ + public Class getType() { + return type; } } - public static class UpdateEvent extends KeyValueEvent { + /** + * @author Christoph Strobl + * @param + */ + @SuppressWarnings("serial") + abstract static class KeyBasedEventWithPayload extends KeyBasedEvent { - private static final long serialVersionUID = -1; + private final T payload; - UpdateEvent(Object source, Type type, String keyspace, Serializable id, Object value) { - super(source, type, keyspace, id, value); + public KeyBasedEventWithPayload(Serializable key, String keySpace, Class type, T payload) { + super(key, keySpace, type); + this.payload = payload; + } + + /** + * Get the value of the element the {@link KeyValueEvent} refers to. Can be {@literal null}. + * + * @return + */ + public T getPayload() { + return payload; } } - public static class DeleteEvent extends KeyValueEvent { + /** + * {@link KeyValueEvent} raised before loading an object by its {@literal key}. + * + * @author Christoph Strobl + * @param + */ + @SuppressWarnings("serial") + public static class BeforeGetEvent extends KeyBasedEvent { - 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); + protected BeforeGetEvent(Serializable key, String keySpace, Class type) { + super(key, keySpace, type); } } + /** + * {@link KeyValueEvent} after loading an object by its {@literal key}. + * + * @author Christoph Strobl + * @param + */ + @SuppressWarnings("serial") + public static class AfterGetEvent extends KeyBasedEventWithPayload { + + protected AfterGetEvent(Serializable key, String keyspace, Class type, T payload) { + super(key, keyspace, type, payload); + } + + } + + /** + * {@link KeyValueEvent} before inserting an object by with a given {@literal key}. + * + * @author Christoph Strobl + * @param + */ + @SuppressWarnings("serial") + public static class BeforeInsertEvent extends KeyBasedEventWithPayload { + + public BeforeInsertEvent(Serializable key, String keySpace, Class type, T payload) { + super(key, keySpace, type, payload); + + } + } + + /** + * {@link KeyValueEvent} after inserting an object by with a given {@literal key}. + * + * @author Christoph Strobl + * @param + */ + @SuppressWarnings("serial") + public static class AfterInsertEvent extends KeyBasedEventWithPayload { + + public AfterInsertEvent(Serializable key, String keySpace, Class type, T payload) { + super(key, keySpace, type, payload); + } + } + + /** + * {@link KeyValueEvent} before updating an object by with a given {@literal key}. + * + * @author Christoph Strobl + * @param + */ + @SuppressWarnings("serial") + public static class BeforeUpdateEvent extends KeyBasedEventWithPayload { + + public BeforeUpdateEvent(Serializable key, String keySpace, Class type, T payload) { + super(key, keySpace, type, payload); + } + } + + /** + * {@link KeyValueEvent} after updating an object by with a given {@literal key}. + * + * @author Christoph Strobl + * @param + */ + @SuppressWarnings("serial") + public static class AfterUpdateEvent extends KeyBasedEventWithPayload { + + private final Object existing; + + public AfterUpdateEvent(Serializable key, String keySpace, Class type, T payload, Object existing) { + super(key, keySpace, type, payload); + this.existing = existing; + } + + /** + * Get the value before update. Can be {@literal null}. + * + * @return + */ + public Object before() { + return existing; + } + + /** + * Get the current value. + * + * @return + */ + public T after() { + return getPayload(); + } + } + + /** + * {@link KeyValueEvent} before removing an object by with a given {@literal key}. + * + * @author Christoph Strobl + * @param + */ + @SuppressWarnings("serial") + public static class BeforeDeleteEvent extends KeyBasedEvent { + + public BeforeDeleteEvent(Serializable key, String keySpace, Class type) { + super(key, keySpace, type); + } + } + + /** + * {@link KeyValueEvent} after removing an object by with a given {@literal key}. + * + * @author Christoph Strobl + * @param + */ + @SuppressWarnings("serial") + public static class AfterDeleteEvent extends KeyBasedEventWithPayload { + + public AfterDeleteEvent(Serializable key, String keySpace, Class type, T payload) { + super(key, keySpace, type, payload); + } + } + + /** + * {@link KeyValueEvent} before removing all elements in a given {@literal keySpace}. + * + * @author Christoph Strobl + * @param + */ + @SuppressWarnings("serial") + public static class BeforeDropKeySpaceEvent extends KeyValueEvent { + + public BeforeDropKeySpaceEvent(String keySpace, Class type) { + super(type, keySpace); + } + + @Override + @SuppressWarnings("unchecked") + public Class getSource() { + return (Class) super.getSource(); + } + + } + + /** + * {@link KeyValueEvent} after removing all elements in a given {@literal keySpace}. + * + * @author Christoph Strobl + * @param + */ + @SuppressWarnings("serial") + public static class AfterDropKeySpaceEvent extends KeyValueEvent { + + public AfterDropKeySpaceEvent(String keySpace, Class type) { + super(type, keySpace); + } + + @Override + @SuppressWarnings("unchecked") + public Class getSource() { + return (Class) super.getSource(); + } + } } 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 189f338..55f9a95 100644 --- a/src/test/java/org/springframework/data/keyvalue/core/KeyValueTemplateUnitTests.java +++ b/src/test/java/org/springframework/data/keyvalue/core/KeyValueTemplateUnitTests.java @@ -24,6 +24,7 @@ import static org.mockito.Mockito.*; import java.io.Serializable; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.HashSet; import org.junit.Before; @@ -32,21 +33,25 @@ import org.junit.Test; import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; +import org.mockito.Matchers; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; -import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.dao.DuplicateKeyException; import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.annotation.Id; import org.springframework.data.keyvalue.TypeWithCustomComposedKeySpaceAnnotation; import org.springframework.data.keyvalue.SubclassOfTypeWithCustomComposedKeySpaceAnnotation; 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.event.KeyValueEvent.AfterDeleteEvent; +import org.springframework.data.keyvalue.core.event.KeyValueEvent.AfterDropKeySpaceEvent; +import org.springframework.data.keyvalue.core.event.KeyValueEvent.AfterGetEvent; +import org.springframework.data.keyvalue.core.event.KeyValueEvent.AfterInsertEvent; +import org.springframework.data.keyvalue.core.event.KeyValueEvent.AfterUpdateEvent; +import org.springframework.data.keyvalue.core.event.KeyValueEvent.BeforeDeleteEvent; +import org.springframework.data.keyvalue.core.event.KeyValueEvent.BeforeGetEvent; +import org.springframework.data.keyvalue.core.event.KeyValueEvent.BeforeInsertEvent; +import org.springframework.data.keyvalue.core.event.KeyValueEvent.BeforeUpdateEvent; import org.springframework.data.keyvalue.core.query.KeyValueQuery; import org.springframework.util.ObjectUtils; @@ -68,12 +73,12 @@ public class KeyValueTemplateUnitTests { private @Mock KeyValueAdapter adapterMock; private KeyValueTemplate template; - private @Mock ApplicationContext ctxMock; + private @Mock ApplicationEventPublisher publisherMock; @Before public void setUp() throws InstantiationException, IllegalAccessException { this.template = new KeyValueTemplate(adapterMock); - this.template.setApplicationContext(ctxMock); + this.template.setApplicationEventPublisher(publisherMock); } /** @@ -431,219 +436,270 @@ public class KeyValueTemplateUnitTests { @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.setApplicationEventPublisher(null); template.insert("1", FOO_ONE); - verifyZeroInteractions(ctxMock); + verifyZeroInteractions(publisherMock); + } + + /** + * @see DATAKV-104 + */ + @Test + public void shouldNotPublishEventsWhenEventsToPublishIsSetToNull() { + + template.setEventTypesToPublish(null); + + template.insert("1", FOO_ONE); + + verifyZeroInteractions(publisherMock); + } + + /** + * @see DATAKV-104 + */ + @Test + @SuppressWarnings("rawtypes") + public void shouldNotPublishEventsWhenEventsToPublishIsSetToEmptyList() { + + template.setEventTypesToPublish(Collections.> emptySet()); + + template.insert("1", FOO_ONE); + + verifyZeroInteractions(publisherMock); + } + + /** + * @see DATAKV-104 + */ + @Test + public void shouldPublishEventsByDefault() { + + template.insert("1", FOO_ONE); + + verify(publisherMock, atLeastOnce()).publishEvent(Matchers.any(KeyValueEvent.class)); } /** * @see DATAKV-91 + * @see DATAKV-104 */ @Test + @SuppressWarnings({ "unchecked", }) public void shouldNotPublishEventWhenNotExplicitlySetForPublication() { - template.setEventTypesToPublish(new HashSet(Arrays.asList(KeyValueEvent.Type.AFTER_DELETE))); + setEventsToPublish(BeforeDeleteEvent.class); template.insert("1", FOO_ONE); - verifyZeroInteractions(ctxMock); + verifyZeroInteractions(publisherMock); } /** * @see DATAKV-91 + * @see DATAKV-104 */ @Test + @SuppressWarnings({ "unchecked", "rawtypes" }) public void shouldPublishBeforeInsertEventCorrectly() { - template.setEventTypesToPublish(new HashSet(Arrays.asList(KeyValueEvent.Type.BEFORE_INSERT))); + setEventsToPublish(BeforeInsertEvent.class); template.insert("1", FOO_ONE); - ArgumentCaptor captor = ArgumentCaptor.forClass(InsertEvent.class); + ArgumentCaptor captor = ArgumentCaptor.forClass(BeforeInsertEvent.class); - verify(ctxMock, times(1)).publishEvent(captor.capture()); - verifyNoMoreInteractions(ctxMock); + verify(publisherMock, times(1)).publishEvent(captor.capture()); + verifyNoMoreInteractions(publisherMock); - assertThat(captor.getValue().getType(), is(Type.BEFORE_INSERT)); - assertThat(captor.getValue().getId(), is((Serializable) "1")); + assertThat(captor.getValue().getKey(), is((Serializable) "1")); assertThat(captor.getValue().getKeyspace(), is(Foo.class.getName())); - assertThat(captor.getValue().getValue(), is((Object) FOO_ONE)); + assertThat(captor.getValue().getPayload(), is((Object) FOO_ONE)); } /** * @see DATAKV-91 + * @see DATAKV-104 */ @Test + @SuppressWarnings({ "unchecked", "rawtypes" }) public void shouldPublishAfterInsertEventCorrectly() { - template.setEventTypesToPublish(new HashSet(Arrays.asList(KeyValueEvent.Type.AFTER_INSERT))); + setEventsToPublish(AfterInsertEvent.class); template.insert("1", FOO_ONE); - ArgumentCaptor captor = ArgumentCaptor.forClass(InsertEvent.class); + ArgumentCaptor captor = ArgumentCaptor.forClass(AfterInsertEvent.class); - verify(ctxMock, times(1)).publishEvent(captor.capture()); - verifyNoMoreInteractions(ctxMock); + verify(publisherMock, times(1)).publishEvent(captor.capture()); + verifyNoMoreInteractions(publisherMock); - assertThat(captor.getValue().getType(), is(Type.AFTER_INSERT)); - assertThat(captor.getValue().getId(), is((Serializable) "1")); + assertThat(captor.getValue().getKey(), is((Serializable) "1")); assertThat(captor.getValue().getKeyspace(), is(Foo.class.getName())); - assertThat(captor.getValue().getValue(), is((Object) FOO_ONE)); + assertThat(captor.getValue().getPayload(), is((Object) FOO_ONE)); } /** * @see DATAKV-91 + * @see DATAKV-104 */ @Test + @SuppressWarnings({ "unchecked", "rawtypes" }) public void shouldPublishBeforeUpdateEventCorrectly() { - template.setEventTypesToPublish(new HashSet(Arrays.asList(KeyValueEvent.Type.BEFORE_UPDATE))); + setEventsToPublish(BeforeUpdateEvent.class); template.update("1", FOO_ONE); - ArgumentCaptor captor = ArgumentCaptor.forClass(UpdateEvent.class); + ArgumentCaptor captor = ArgumentCaptor.forClass(BeforeUpdateEvent.class); - verify(ctxMock, times(1)).publishEvent(captor.capture()); - verifyNoMoreInteractions(ctxMock); + verify(publisherMock, times(1)).publishEvent(captor.capture()); + verifyNoMoreInteractions(publisherMock); - assertThat(captor.getValue().getType(), is(Type.BEFORE_UPDATE)); - assertThat(captor.getValue().getId(), is((Serializable) "1")); + assertThat(captor.getValue().getKey(), is((Serializable) "1")); assertThat(captor.getValue().getKeyspace(), is(Foo.class.getName())); - assertThat(captor.getValue().getValue(), is((Object) FOO_ONE)); + assertThat(captor.getValue().getPayload(), is((Object) FOO_ONE)); } /** * @see DATAKV-91 + * @see DATAKV-104 */ @Test + @SuppressWarnings({ "unchecked", "rawtypes" }) public void shouldPublishAfterUpdateEventCorrectly() { - template.setEventTypesToPublish(new HashSet(Arrays.asList(KeyValueEvent.Type.AFTER_UPDATE))); + setEventsToPublish(AfterUpdateEvent.class); template.update("1", FOO_ONE); - ArgumentCaptor captor = ArgumentCaptor.forClass(UpdateEvent.class); + ArgumentCaptor captor = ArgumentCaptor.forClass(AfterUpdateEvent.class); - verify(ctxMock, times(1)).publishEvent(captor.capture()); - verifyNoMoreInteractions(ctxMock); + verify(publisherMock, times(1)).publishEvent(captor.capture()); + verifyNoMoreInteractions(publisherMock); - assertThat(captor.getValue().getType(), is(Type.AFTER_UPDATE)); - assertThat(captor.getValue().getId(), is((Serializable) "1")); + assertThat(captor.getValue().getKey(), is((Serializable) "1")); assertThat(captor.getValue().getKeyspace(), is(Foo.class.getName())); - assertThat(captor.getValue().getValue(), is((Object) FOO_ONE)); + assertThat(captor.getValue().getPayload(), is((Object) FOO_ONE)); } /** * @see DATAKV-91 + * @see DATAKV-104 */ @Test + @SuppressWarnings({ "rawtypes", "unchecked" }) public void shouldPublishBeforeDeleteEventCorrectly() { - template.setEventTypesToPublish(new HashSet(Arrays.asList(KeyValueEvent.Type.BEFORE_DELETE))); + setEventsToPublish(BeforeDeleteEvent.class); template.delete("1", FOO_ONE.getClass()); - ArgumentCaptor captor = ArgumentCaptor.forClass(DeleteEvent.class); + ArgumentCaptor captor = ArgumentCaptor.forClass(BeforeDeleteEvent.class); - verify(ctxMock, times(1)).publishEvent(captor.capture()); - verifyNoMoreInteractions(ctxMock); + verify(publisherMock, times(1)).publishEvent(captor.capture()); + verifyNoMoreInteractions(publisherMock); - assertThat(captor.getValue().getType(), is(Type.BEFORE_DELETE)); - assertThat(captor.getValue().getId(), is((Serializable) "1")); + assertThat(captor.getValue().getKey(), is((Serializable) "1")); assertThat(captor.getValue().getKeyspace(), is(Foo.class.getName())); - assertThat(captor.getValue().getValue(), nullValue()); } /** * @see DATAKV-91 + * @see DATAKV-104 */ @Test + @SuppressWarnings({ "rawtypes", "unchecked" }) public void shouldPublishAfterDeleteEventCorrectly() { - template.setEventTypesToPublish(new HashSet(Arrays.asList(KeyValueEvent.Type.AFTER_DELETE))); + setEventsToPublish(AfterDeleteEvent.class); 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); + ArgumentCaptor captor = ArgumentCaptor.forClass(AfterDeleteEvent.class); - verify(ctxMock, times(1)).publishEvent(captor.capture()); - verifyNoMoreInteractions(ctxMock); + verify(publisherMock, times(1)).publishEvent(captor.capture()); + verifyNoMoreInteractions(publisherMock); - assertThat(captor.getValue().getType(), is(Type.AFTER_DELETE)); - assertThat(captor.getValue().getId(), is((Serializable) "1")); + assertThat(captor.getValue().getKey(), is((Serializable) "1")); assertThat(captor.getValue().getKeyspace(), is(Foo.class.getName())); - assertThat(captor.getValue().getValue(), is((Object) FOO_ONE)); + assertThat(captor.getValue().getPayload(), is((Object) FOO_ONE)); } /** * @see DATAKV-91 + * @see DATAKV-104 */ @Test + @SuppressWarnings({ "rawtypes", "unchecked" }) public void shouldPublishBeforeGetEventCorrectly() { - template.setEventTypesToPublish(new HashSet(Arrays.asList(KeyValueEvent.Type.BEFORE_GET))); + setEventsToPublish(BeforeGetEvent.class); + 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); + ArgumentCaptor captor = ArgumentCaptor.forClass(BeforeGetEvent.class); - verify(ctxMock, times(1)).publishEvent(captor.capture()); - verifyNoMoreInteractions(ctxMock); + verify(publisherMock, times(1)).publishEvent(captor.capture()); + verifyNoMoreInteractions(publisherMock); - assertThat(captor.getValue().getType(), is(Type.BEFORE_GET)); - assertThat(captor.getValue().getId(), is((Serializable) "1")); + assertThat(captor.getValue().getKey(), is((Serializable) "1")); assertThat(captor.getValue().getKeyspace(), is(Foo.class.getName())); - assertThat(captor.getValue().getValue(), nullValue()); } /** * @see DATAKV-91 + * @see DATAKV-104 */ @Test + @SuppressWarnings({ "rawtypes", "unchecked" }) public void shouldPublishAfterGetEventCorrectly() { - template.setEventTypesToPublish(new HashSet(Arrays.asList(KeyValueEvent.Type.AFTER_GET))); + setEventsToPublish(AfterGetEvent.class); + 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); + ArgumentCaptor captor = ArgumentCaptor.forClass(AfterGetEvent.class); - verify(ctxMock, times(1)).publishEvent(captor.capture()); - verifyNoMoreInteractions(ctxMock); + verify(publisherMock, times(1)).publishEvent(captor.capture()); + verifyNoMoreInteractions(publisherMock); - assertThat(captor.getValue().getType(), is(Type.AFTER_GET)); - assertThat(captor.getValue().getId(), is((Serializable) "1")); + assertThat(captor.getValue().getKey(), is((Serializable) "1")); assertThat(captor.getValue().getKeyspace(), is(Foo.class.getName())); - assertThat(captor.getValue().getValue(), is((Object) FOO_ONE)); + assertThat(captor.getValue().getPayload(), is((Object) FOO_ONE)); } /** * @see DATAKV-91 + * @see DATAKV-104 */ @Test + @SuppressWarnings({ "rawtypes", "unchecked" }) public void shouldPublishDropKeyspaceEventCorrectly() { - template.setEventTypesToPublish(new HashSet(Arrays.asList(KeyValueEvent.Type.AFTER_DELETE))); + setEventsToPublish(AfterDropKeySpaceEvent.class); template.delete(FOO_ONE.getClass()); - ArgumentCaptor captor = ArgumentCaptor.forClass(DropKeyspaceEvent.class); + ArgumentCaptor captor = ArgumentCaptor.forClass(AfterDropKeySpaceEvent.class); - verify(ctxMock, times(1)).publishEvent(captor.capture()); - verifyNoMoreInteractions(ctxMock); + verify(publisherMock, times(1)).publishEvent(captor.capture()); + verifyNoMoreInteractions(publisherMock); - assertThat(captor.getValue().getType(), is(Type.AFTER_DELETE)); assertThat(captor.getValue().getKeyspace(), is(Foo.class.getName())); } + @SuppressWarnings("unchecked") + private void setEventsToPublish(Class... events) { + template.setEventTypesToPublish(new HashSet>(Arrays.asList(events))); + } + static class Foo { String foo;