diff --git a/apache-geode-extensions/src/main/java/org/springframework/geode/distributed/MembershipListenerAdapter.java b/apache-geode-extensions/src/main/java/org/springframework/geode/distributed/MembershipListenerAdapter.java
deleted file mode 100644
index 27d54e0b..00000000
--- a/apache-geode-extensions/src/main/java/org/springframework/geode/distributed/MembershipListenerAdapter.java
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * Copyright 2020 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
- *
- * https://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.geode.distributed;
-
-import java.util.List;
-import java.util.Optional;
-import java.util.Set;
-import java.util.function.BiConsumer;
-import java.util.function.Consumer;
-
-import org.apache.geode.cache.Cache;
-import org.apache.geode.distributed.internal.DistributionManager;
-import org.apache.geode.distributed.internal.InternalDistributedSystem;
-import org.apache.geode.distributed.internal.MembershipListener;
-import org.apache.geode.distributed.internal.membership.InternalDistributedMember;
-
-import org.springframework.geode.util.function.QuadConsumer;
-import org.springframework.geode.util.function.TriConsumer;
-
-/**
- * A {@link MembershipListener} implementation using the
- * Adapter Software Design Pattern
- * to delegate membership event callbacks to a {@link Consumer} of those membership events.
- *
- * @author John Blum
- * @see java.util.function.BiConsumer
- * @see java.util.function.Consumer
- * @see org.apache.geode.distributed.internal.DistributionManager
- * @see org.apache.geode.distributed.internal.MembershipListener
- * @see org.apache.geode.distributed.internal.membership.InternalDistributedMember
- * @since 1.3.0
- */
-@SuppressWarnings("unused")
-public class MembershipListenerAdapter implements MembershipListener {
-
- /**
- * Factory method used to construct a new instance of the {@link MembershipListenerAdapter}.
- *
- * @return a new instance of {@link MembershipListenerAdapter}.
- */
- public static MembershipListenerAdapter create() {
- return new MembershipListenerAdapter();
- }
-
- private TriConsumer memberDepartedConsumer =
- (manager, member, crashed) -> {};
-
- private BiConsumer memberJoinedConsumer = (manager, member) -> {};
-
- private QuadConsumer memberSuspectConsumer =
- (manage, member, suspect, reason) -> {};
-
- private TriConsumer, List> quorumLostConsumer =
- (manager, failures, remaining) -> {};
-
- /**
- * @inheritDoc
- */
- @Override
- public void memberDeparted(DistributionManager distributionManager, InternalDistributedMember distributedMember,
- boolean crashed) {
-
- this.memberDepartedConsumer.accept(distributionManager, distributedMember, crashed);
- }
-
- /**
- * @inheritDoc
- */
- @Override
- public void memberJoined(DistributionManager distributionManager, InternalDistributedMember distributedMember) {
- this.memberJoinedConsumer.accept(distributionManager, distributedMember);
- }
-
- /**
- * @inheritDoc
- */
- @Override
- public void memberSuspect(DistributionManager distributionManager, InternalDistributedMember distributedMember,
- InternalDistributedMember whoSuspected, String reason) {
-
- this.memberSuspectConsumer.accept(distributionManager, distributedMember, whoSuspected, reason);
- }
-
- /**
- * @inheritDoc
- */
- @Override
- public void quorumLost(DistributionManager distributionManager, Set failures,
- List remaining) {
-
- this.quorumLostConsumer.accept(distributionManager, failures, remaining);
- }
-
- /**
- * Registers this {@link MembershipListener} with the given {@literal peer} {@link Cache}.
- *
- * @param peerCache {@literal peer} {@link Cache} on which to register this {@link MembershipListener}.
- * @return this {@link MembershipListenerAdapter}.
- * @see org.apache.geode.cache.Cache
- */
- public MembershipListenerAdapter register(Cache peerCache) {
-
- Optional.ofNullable(peerCache)
- .map(Cache::getDistributedSystem)
- .filter(InternalDistributedSystem.class::isInstance)
- .map(InternalDistributedSystem.class::cast)
- .map(InternalDistributedSystem::getDistributionManager)
- .ifPresent(distributionManager -> distributionManager
- .addMembershipListener(this));
-
- return this;
- }
-
- /**
- * Null-safe builder method used to add a {@link #memberDeparted(DistributionManager, InternalDistributedMember, boolean)}
- * {@link TriConsumer} event handler.
- *
- * @param memberDepartedConsumer {@link TriConsumer} handling {@literal memberDeparted} events.
- * @return this {@link MembershipListenerAdapter}.
- * @see org.springframework.geode.util.function.TriConsumer
- */
- public MembershipListenerAdapter withMemberDepartedConsumer(
- TriConsumer memberDepartedConsumer) {
-
- if (memberDepartedConsumer != null) {
- this.memberDepartedConsumer = memberDepartedConsumer;
- }
-
- return this;
- }
-
- /**
- * Null-safe builder method used to add a {@link #memberJoined(DistributionManager, InternalDistributedMember)}
- * {@link BiConsumer} event handler.
- *
- * @param memberJoinedConsumer {@link BiConsumer} handling {@literal memberJoined} events.
- * @return this {@link MembershipListenerAdapter}.
- * @see java.util.function.BiConsumer
- */
- public MembershipListenerAdapter withMemberJoinedConsumer(
- BiConsumer memberJoinedConsumer) {
-
- if (memberJoinedConsumer != null) {
- this.memberJoinedConsumer = memberJoinedConsumer;
- }
-
- return this;
- }
-
- /**
- * Null-safe builder method used to add a {@link #memberSuspect(DistributionManager, InternalDistributedMember, InternalDistributedMember, String)}
- * {@link QuadConsumer} event handler.
- *
- * @param memberSuspectConsumer {@link QuadConsumer} handling {@literal memberSuspect} events.
- * @return this {@link MembershipListenerAdapter}.
- * @see org.springframework.geode.util.function.QuadConsumer
- */
- public MembershipListenerAdapter withMemberSuspectConsumer(
- QuadConsumer memberSuspectConsumer) {
-
- if (memberSuspectConsumer != null) {
- this.memberSuspectConsumer = memberSuspectConsumer;
- }
-
- return this;
- }
-
- /**
- * Null-safe build method used to add a {@link #quorumLost(DistributionManager, Set, List)} {@link TriConsumer}
- * event handler.
- *
- * @param quorumLostConsumer {@link TriConsumer} handling {@literal quorumLost} events.
- * @return this {@link MembershipListenerAdapter}.
- * @see org.springframework.geode.util.function.TriConsumer
- */
- public MembershipListenerAdapter withQuorumLostConsumer(
- TriConsumer, List> quorumLostConsumer) {
-
- if (quorumLostConsumer != null) {
- this.quorumLostConsumer = quorumLostConsumer;
- }
-
- return this;
- }
-}
diff --git a/apache-geode-extensions/src/main/java/org/springframework/geode/distributed/event/MembershipListenerAdapter.java b/apache-geode-extensions/src/main/java/org/springframework/geode/distributed/event/MembershipListenerAdapter.java
new file mode 100644
index 00000000..eee24418
--- /dev/null
+++ b/apache-geode-extensions/src/main/java/org/springframework/geode/distributed/event/MembershipListenerAdapter.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2020 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
+ *
+ * https://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.geode.distributed.event;
+
+import java.util.EventListener;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+
+import org.apache.geode.cache.Cache;
+import org.apache.geode.distributed.internal.DistributionManager;
+import org.apache.geode.distributed.internal.InternalDistributedSystem;
+import org.apache.geode.distributed.internal.MembershipListener;
+import org.apache.geode.distributed.internal.membership.InternalDistributedMember;
+
+import org.springframework.geode.distributed.event.support.MemberDepartedEvent;
+import org.springframework.geode.distributed.event.support.MemberJoinedEvent;
+import org.springframework.geode.distributed.event.support.MemberSuspectEvent;
+import org.springframework.geode.distributed.event.support.QuorumLostEvent;
+
+/**
+ * An abstract {@link MembershipListener} implementation using the
+ * Adapter Software Design Pattern
+ * to delegate membership event callbacks to event handlers for those membership events.
+ *
+ * @author John Blum
+ * @param specific {@link Class sub-type} of this {@link MembershipListenerAdapter}.
+ * @see java.util.EventListener
+ * @see org.apache.geode.cache.Cache
+ * @see org.apache.geode.distributed.internal.DistributionManager
+ * @see org.apache.geode.distributed.internal.InternalDistributedSystem
+ * @see org.apache.geode.distributed.internal.MembershipListener
+ * @see org.apache.geode.distributed.internal.membership.InternalDistributedMember
+ * @since 1.3.0
+ */
+@SuppressWarnings("unused")
+public abstract class MembershipListenerAdapter>
+ implements EventListener, MembershipListener {
+
+ /**
+ * @inheritDoc
+ */
+ @Override
+ public final void memberDeparted(DistributionManager manager, InternalDistributedMember member, boolean crashed) {
+
+ MemberDepartedEvent event = new MemberDepartedEvent(manager)
+ .withMember(member)
+ .crashed(crashed);
+
+ handleMemberDeparted(event);
+ }
+
+ public void handleMemberDeparted(MemberDepartedEvent event) { }
+
+ /**
+ * @inheritDoc
+ */
+ @Override
+ public final void memberJoined(DistributionManager manager, InternalDistributedMember member) {
+
+ MemberJoinedEvent event = new MemberJoinedEvent(manager)
+ .withMember(member);
+
+ handleMemberJoined(event);
+ }
+
+ public void handleMemberJoined(MemberJoinedEvent event) { }
+
+ /**
+ * @inheritDoc
+ */
+ @Override
+ public final void memberSuspect(DistributionManager manager, InternalDistributedMember member,
+ InternalDistributedMember suspectMember, String reason) {
+
+ MemberSuspectEvent event = new MemberSuspectEvent(manager)
+ .withMember(member)
+ .withReason(reason)
+ .withSuspect(suspectMember);
+
+ handleMemberSuspect(event);
+ }
+
+ public void handleMemberSuspect(MemberSuspectEvent event) { }
+
+ /**
+ * @inheritDoc
+ */
+ @Override
+ public final void quorumLost(DistributionManager manager, Set failedMembers,
+ List remainingMembers) {
+
+ QuorumLostEvent event = new QuorumLostEvent(manager)
+ .withFailedMembers(failedMembers)
+ .withRemainingMembers(remainingMembers);
+
+ handleQuorumLost(event);
+ }
+
+ public void handleQuorumLost(QuorumLostEvent event) { }
+
+ /**
+ * Registers this {@link MembershipListener} with the given {@literal peer} {@link Cache}.
+ *
+ * @param peerCache {@literal peer} {@link Cache} on which to register this {@link MembershipListener}.
+ * @return this {@link MembershipListenerAdapter}.
+ * @see org.apache.geode.cache.Cache
+ */
+ @SuppressWarnings("unchecked")
+ public T register(Cache peerCache) {
+
+ Optional.ofNullable(peerCache)
+ .map(Cache::getDistributedSystem)
+ .filter(InternalDistributedSystem.class::isInstance)
+ .map(InternalDistributedSystem.class::cast)
+ .map(InternalDistributedSystem::getDistributionManager)
+ .ifPresent(distributionManager -> distributionManager
+ .addMembershipListener(this));
+
+ return (T) this;
+ }
+}
diff --git a/apache-geode-extensions/src/test/java/org/springframework/geode/distributed/MembershipListenerAdapterUnitTests.java b/apache-geode-extensions/src/test/java/org/springframework/geode/distributed/MembershipListenerAdapterUnitTests.java
deleted file mode 100644
index 71fa7812..00000000
--- a/apache-geode-extensions/src/test/java/org/springframework/geode/distributed/MembershipListenerAdapterUnitTests.java
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- * Copyright 2020 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
- *
- * https://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.geode.distributed;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoInteractions;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-import java.util.function.BiConsumer;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnitRunner;
-
-import org.apache.geode.cache.Cache;
-import org.apache.geode.distributed.DistributedSystem;
-import org.apache.geode.distributed.internal.DistributionManager;
-import org.apache.geode.distributed.internal.InternalDistributedSystem;
-import org.apache.geode.distributed.internal.membership.InternalDistributedMember;
-
-import org.springframework.geode.util.function.QuadConsumer;
-import org.springframework.geode.util.function.TriConsumer;
-
-/**
- * Unit Tests for {@link MembershipListenerAdapter}.
- *
- * @author John Blum
- * @see org.junit.Test
- * @see org.mockito.Mockito
- * @see org.mockito.junit.MockitoJUnitRunner
- * @see org.apache.geode.distributed.internal.DistributionManager
- * @see org.apache.geode.distributed.internal.membership.InternalDistributedMember
- * @see org.springframework.geode.distributed.MembershipListenerAdapter
- * @since 1.3.0
- */
-@RunWith(MockitoJUnitRunner.class)
-public class MembershipListenerAdapterUnitTests {
-
- @Mock
- private DistributionManager mockDistributionManager;
-
- @Mock
- private InternalDistributedMember mockDistributedMember;
-
- @Test
- public void createConstructsNewMembershipListenerAdapterWithNoOpEventHandlers() {
-
- InternalDistributedMember mockSuspectMember = mock(InternalDistributedMember.class);
-
- MembershipListenerAdapter membershipListener = MembershipListenerAdapter.create();
-
- assertThat(membershipListener).isNotNull();
-
- membershipListener.memberDeparted(this.mockDistributionManager, this.mockDistributedMember, true);
- membershipListener.memberJoined(this.mockDistributionManager, this.mockDistributedMember);
- membershipListener.memberSuspect(this.mockDistributionManager, this.mockDistributedMember, mockSuspectMember,
- "System is unstable!!");
- membershipListener.quorumLost(this.mockDistributionManager, Collections.singleton(mockSuspectMember),
- Collections.singletonList(this.mockDistributedMember));
-
- verifyNoInteractions(this.mockDistributedMember);
- verifyNoInteractions(this.mockDistributedMember);
- verifyNoInteractions(mockSuspectMember);
- }
-
- @Test
- public void registersListenerWithPeerCache() {
-
- Cache mockCache = mock(Cache.class);
-
- DistributionManager mockDistributionManager = mock(DistributionManager.class);
-
- InternalDistributedSystem mockDistributedSystem = mock(InternalDistributedSystem.class);
-
- doReturn(mockDistributedSystem).when(mockCache).getDistributedSystem();
- doReturn(mockDistributionManager).when(mockDistributedSystem).getDistributionManager();
-
- MembershipListenerAdapter membershipListener = new MembershipListenerAdapter();
-
- assertThat(membershipListener.register(mockCache)).isSameAs(membershipListener);
-
- verify(mockCache, times(1)).getDistributedSystem();
- verify(mockDistributedSystem, times(1)).getDistributionManager();
- verify(mockDistributionManager, times(1)).addMembershipListener(eq(membershipListener));
- }
-
- @Test
- public void registerListenerWithNullCacheIsNullSafe() {
-
- MembershipListenerAdapter membershipListener = new MembershipListenerAdapter();
-
- assertThat(membershipListener.register(null)).isSameAs(membershipListener);
- }
-
- @Test
- public void registerListenerWithNullDistributedSystemIsNullSafe() {
-
- Cache mockCache = mock(Cache.class);
-
- MembershipListenerAdapter membershipListener = new MembershipListenerAdapter();
-
- assertThat(membershipListener.register(mockCache)).isSameAs(membershipListener);
-
- verify(mockCache, times(1)).getDistributedSystem();
- }
-
- @Test
- public void registerListenerWithNonInternalDistributedSystemIsSafe() {
-
- Cache mockCache = mock(Cache.class);
-
- DistributedSystem mockDistributedSystem = mock(DistributedSystem.class);
-
- MembershipListenerAdapter membershipListener = new MembershipListenerAdapter();
-
- assertThat(membershipListener.register(mockCache)).isSameAs(membershipListener);
-
- verify(mockCache, times(1)).getDistributedSystem();
- verifyNoInteractions(mockDistributedSystem);
- }
-
- @Test
- public void registerListenerWithNullDistributionManagerIsNullSafe() {
-
- Cache mockCache = mock(Cache.class);
-
- InternalDistributedSystem mockDistributedSystem = mock(InternalDistributedSystem.class);
-
- doReturn(mockDistributedSystem).when(mockCache).getDistributedSystem();
-
- MembershipListenerAdapter membershipListener = new MembershipListenerAdapter();
-
- assertThat(membershipListener.register(mockCache)).isSameAs(membershipListener);
-
- verify(mockCache, times(1)).getDistributedSystem();
- verify(mockDistributedSystem, times(1)).getDistributionManager();
- }
-
- @Test
- @SuppressWarnings("unchecked")
- public void withMemberDepartedEventHandler() {
-
- TriConsumer mockConsumer = mock(TriConsumer.class);
-
- MembershipListenerAdapter membershipListener = MembershipListenerAdapter.create()
- .withMemberDepartedConsumer(mockConsumer);
-
- assertThat(membershipListener).isNotNull();
-
- membershipListener.memberDeparted(this.mockDistributionManager, this.mockDistributedMember, true);
-
- verify(mockConsumer, times(1))
- .accept(eq(this.mockDistributionManager), eq(this.mockDistributedMember), eq(true));
- }
-
- @Test
- @SuppressWarnings("unchecked")
- public void withMemberJoinedEventHandler() {
-
- BiConsumer mockConsumer = mock(BiConsumer.class);
-
- MembershipListenerAdapter membershipListener = MembershipListenerAdapter.create()
- .withMemberJoinedConsumer(mockConsumer);
-
- assertThat(membershipListener).isNotNull();
-
- membershipListener.memberJoined(this.mockDistributionManager, this.mockDistributedMember);
-
- verify(mockConsumer, times(1))
- .accept(eq(this.mockDistributionManager), eq(this.mockDistributedMember));
- }
-
- @Test
- @SuppressWarnings("unchecked")
- public void withMemberSuspectEventHandler() {
-
- QuadConsumer mockConsumer =
- mock(QuadConsumer.class);
-
- InternalDistributedMember mockSuspectMember = mock(InternalDistributedMember.class);
-
- MembershipListenerAdapter membershipListener = MembershipListenerAdapter.create()
- .withMemberSuspectConsumer(mockConsumer);
-
- assertThat(membershipListener).isNotNull();
-
- membershipListener.memberSuspect(this.mockDistributionManager, this.mockDistributedMember, mockSuspectMember,
- "System is a lost cause!!");
-
- verify(mockConsumer, times(1))
- .accept(eq(this.mockDistributionManager), eq(this.mockDistributedMember), eq(mockSuspectMember),
- eq("System is a lost cause!!"));
- }
-
- @Test
- @SuppressWarnings("unchecked")
- public void withQuorumLostEventHandler() {
-
- TriConsumer, List> mockConsumer
- = mock(TriConsumer.class);
-
- MembershipListenerAdapter membershipListener = MembershipListenerAdapter.create()
- .withQuorumLostConsumer(mockConsumer);
-
- assertThat(membershipListener).isNotNull();
-
- membershipListener.quorumLost(this.mockDistributionManager, Collections.singleton(this.mockDistributedMember),
- Collections.singletonList(this.mockDistributedMember));
-
- verify(mockConsumer, times(1)).accept(eq(this.mockDistributionManager),
- eq(Collections.singleton(this.mockDistributedMember)),
- eq(Collections.singletonList(this.mockDistributedMember)));
- }
-}
diff --git a/apache-geode-extensions/src/test/java/org/springframework/geode/distributed/event/MembershipListenerAdapterUnitTests.java b/apache-geode-extensions/src/test/java/org/springframework/geode/distributed/event/MembershipListenerAdapterUnitTests.java
new file mode 100644
index 00000000..4e5f7ef8
--- /dev/null
+++ b/apache-geode-extensions/src/test/java/org/springframework/geode/distributed/event/MembershipListenerAdapterUnitTests.java
@@ -0,0 +1,259 @@
+/*
+ * Copyright 2020 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
+ *
+ * https://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.geode.distributed.event;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isA;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoInteractions;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import org.apache.geode.cache.Cache;
+import org.apache.geode.distributed.DistributedSystem;
+import org.apache.geode.distributed.internal.DistributionManager;
+import org.apache.geode.distributed.internal.InternalDistributedSystem;
+import org.apache.geode.distributed.internal.membership.InternalDistributedMember;
+
+import org.springframework.geode.distributed.event.support.MemberDepartedEvent;
+import org.springframework.geode.distributed.event.support.MemberJoinedEvent;
+import org.springframework.geode.distributed.event.support.MemberSuspectEvent;
+import org.springframework.geode.distributed.event.support.QuorumLostEvent;
+
+/**
+ * Unit Tests for {@link MembershipListenerAdapter}.
+ *
+ * @author John Blum
+ * @see org.junit.Test
+ * @see org.mockito.Mockito
+ * @see org.mockito.junit.MockitoJUnitRunner
+ * @see org.apache.geode.cache.Cache
+ * @see org.apache.geode.distributed.DistributedMember
+ * @see org.apache.geode.distributed.DistributedSystem
+ * @see org.apache.geode.distributed.internal.DistributionManager
+ * @see org.apache.geode.distributed.internal.membership.InternalDistributedMember
+ * @see MembershipListenerAdapter
+ * @since 1.3.0
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class MembershipListenerAdapterUnitTests {
+
+ @Mock
+ private DistributionManager mockDistributionManager;
+
+ @Mock
+ private InternalDistributedMember mockDistributedMember;
+
+ @Mock
+ private InternalDistributedSystem mockDistributedSystem;
+
+ @SuppressWarnings("unchecked")
+ private Set asSet(T... elements) {
+ return new HashSet<>(Arrays.asList(elements));
+ }
+
+ @Test
+ public void memberDepartedCallsHandleMemberDeparted() {
+
+ MembershipListenerAdapter> listener = spy(new TestMembershipListener());
+
+ doAnswer(invocation -> {
+
+ MemberDepartedEvent event = invocation.getArgument(0);
+
+ assertThat(event).isNotNull();
+ assertThat(event.isCrashed()).isTrue();
+ assertThat(event.getDistributedMember().orElse(null)).isEqualTo(this.mockDistributedMember);
+ assertThat(event.getDistributionManager()).isEqualTo(this.mockDistributionManager);
+ assertThat(event.getType()).isEqualTo(MembershipEvent.Type.MEMBER_DEPARTED);
+
+ return null;
+
+ }).when(listener).handleMemberDeparted(any(MemberDepartedEvent.class));
+
+ listener.memberDeparted(this.mockDistributionManager, this.mockDistributedMember, true);
+
+ verify(listener, times(1)).handleMemberDeparted(isA(MemberDepartedEvent.class));
+ }
+
+ @Test
+ public void memberJoinedCallsHandleMemberJoined() {
+
+ MembershipListenerAdapter> listener = spy(new TestMembershipListener());
+
+ doAnswer(invocation -> {
+
+ MemberJoinedEvent event = invocation.getArgument(0);
+
+ assertThat(event).isNotNull();
+ assertThat(event.getDistributedMember().orElse(null)).isEqualTo(this.mockDistributedMember);
+ assertThat(event.getDistributionManager()).isEqualTo(this.mockDistributionManager);
+ assertThat(event.getType()).isEqualTo(MembershipEvent.Type.MEMBER_JOINED);
+
+ return null;
+
+ }).when(listener).handleMemberJoined(any(MemberJoinedEvent.class));
+
+ listener.memberJoined(this.mockDistributionManager, this.mockDistributedMember);
+
+ verify(listener, times(1)).handleMemberJoined(isA(MemberJoinedEvent.class));
+ }
+
+ @Test
+ public void memberSuspectCallsHandleMemberSuspect() {
+
+ InternalDistributedMember suspectMember = mock(InternalDistributedMember.class);
+
+ MembershipListenerAdapter> listener = spy(new TestMembershipListener());
+
+ doAnswer(invocation -> {
+
+ MemberSuspectEvent event = invocation.getArgument(0);
+
+ assertThat(event).isNotNull();
+ assertThat(event.getDistributedMember().orElse(null)).isEqualTo(this.mockDistributedMember);
+ assertThat(event.getDistributionManager()).isEqualTo(this.mockDistributionManager);
+ assertThat(event.getReason().orElse(null)).isEqualTo("The system sucks!");
+ assertThat(event.getSuspectMember().orElse(null)).isEqualTo(suspectMember);
+ assertThat(event.getType()).isEqualTo(MembershipEvent.Type.MEMBER_SUSPECT);
+
+ return null;
+
+ }).when(listener).handleMemberSuspect(any(MemberSuspectEvent.class));
+
+ listener.memberSuspect(this.mockDistributionManager, this.mockDistributedMember, suspectMember,
+ "The system sucks!");
+
+ verify(listener, times(1)).handleMemberSuspect(isA(MemberSuspectEvent.class));
+ }
+
+ @Test
+ public void quorumLostCallsHandleQuorumLost() {
+
+ InternalDistributedMember mockMemberOne = mock(InternalDistributedMember.class);
+ InternalDistributedMember mockMemberTwo = mock(InternalDistributedMember.class);
+
+ MembershipListenerAdapter> listener = spy(new TestMembershipListener());
+
+ doAnswer(invocation -> {
+
+ QuorumLostEvent event = invocation.getArgument(0);
+
+ assertThat(event).isNotNull();
+ assertThat(event.getDistributedMember().orElse(null)).isNull();
+ assertThat(event.getDistributionManager()).isEqualTo(this.mockDistributionManager);
+ assertThat(event.getFailedMembers()).isEqualTo(asSet(mockMemberOne, mockMemberTwo));
+ assertThat(event.getRemainingMembers()).isEqualTo(Collections.singletonList(this.mockDistributedMember));
+ assertThat(event.getType()).isEqualTo(MembershipEvent.Type.QUORUM_LOST);
+
+ return null;
+
+ }).when(listener).handleQuorumLost(any(QuorumLostEvent.class));
+
+ listener.quorumLost(this.mockDistributionManager, asSet(mockMemberOne, mockMemberTwo),
+ Collections.singletonList(this.mockDistributedMember));
+
+ verify(listener, times(1)).handleQuorumLost(isA(QuorumLostEvent.class));
+ }
+
+ @Test
+ public void registersListenerWithPeerCache() {
+
+ Cache mockCache = mock(Cache.class);
+
+ doReturn(this.mockDistributedSystem).when(mockCache).getDistributedSystem();
+ doReturn(this.mockDistributionManager).when(this.mockDistributedSystem).getDistributionManager();
+
+ MembershipListenerAdapter> listener = new TestMembershipListener();
+
+ assertThat(listener.register(mockCache)).isSameAs(listener);
+
+ verify(mockCache, times(1)).getDistributedSystem();
+ verify(this.mockDistributedSystem, times(1)).getDistributionManager();
+ verify(this.mockDistributionManager, times(1))
+ .addMembershipListener(eq(listener));
+ }
+
+ @Test
+ public void registerListenerWithNullCacheIsNullSafe() {
+
+ MembershipListenerAdapter> listener = new TestMembershipListener();
+
+ assertThat(listener.register(null)).isSameAs(listener);
+ }
+
+ @Test
+ public void registerListenerWithNullDistributedSystemIsNullSafe() {
+
+ Cache mockCache = mock(Cache.class);
+
+ MembershipListenerAdapter> listener = new TestMembershipListener();
+
+ assertThat(listener.register(mockCache)).isSameAs(listener);
+
+ verify(mockCache, times(1)).getDistributedSystem();
+ }
+
+ @Test
+ public void registerListenerWithNonInternalDistributedSystemIsSafe() {
+
+ Cache mockCache = mock(Cache.class);
+
+ DistributedSystem mockDistributedSystem = mock(DistributedSystem.class);
+
+ doReturn(mockDistributedSystem).when(mockCache).getDistributedSystem();
+
+ MembershipListenerAdapter> listener = new TestMembershipListener();
+
+ assertThat(listener.register(mockCache)).isSameAs(listener);
+
+ verify(mockCache, times(1)).getDistributedSystem();
+ verifyNoInteractions(mockDistributedSystem);
+ }
+
+ @Test
+ public void registerListenerWithNullDistributionManagerIsNullSafe() {
+
+ Cache mockCache = mock(Cache.class);
+
+ doReturn(this.mockDistributedSystem).when(mockCache).getDistributedSystem();
+
+ MembershipListenerAdapter> listener = new TestMembershipListener();
+
+ assertThat(listener.register(mockCache)).isSameAs(listener);
+
+ verify(mockCache, times(1)).getDistributedSystem();
+ verify(this.mockDistributedSystem, times(1)).getDistributionManager();
+ }
+
+ static class TestMembershipListener extends MembershipListenerAdapter { }
+
+}