From b631ce2146fda5dd6111c84fba8517be54adc8d1 Mon Sep 17 00:00:00 2001 From: Ashmeet Singh Date: Mon, 15 Nov 2021 13:40:46 +0100 Subject: [PATCH 1/5] Add global event listner --- .../com/pusher/client/channel/Channel.java | 51 +++++++++++++++++++ .../client/channel/impl/ChannelImpl.java | 29 ++++++++++- 2 files changed, 79 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/pusher/client/channel/Channel.java b/src/main/java/com/pusher/client/channel/Channel.java index e7cbe752..542038e0 100644 --- a/src/main/java/com/pusher/client/channel/Channel.java +++ b/src/main/java/com/pusher/client/channel/Channel.java @@ -44,6 +44,27 @@ public interface Channel { */ void bind(String eventName, SubscriptionEventListener listener); + /** + * Binds a {@link SubscriptionEventListener} to all events. The + * {@link SubscriptionEventListener} will be notified whenever an + * event is received on this channel. + * + * @param listener + * A listener to receive notifications when the event is + * received. + * @throws IllegalArgumentException + * If the {@link SubscriptionEventListener} is null. + * @throws IllegalStateException + * If the channel has been unsubscribed by calling + * {@link com.pusher.client.Pusher#unsubscribe(String)}. This + * puts the {@linkplain Channel} in a terminal state from which + * it can no longer be used. To resubscribe, call + * {@link com.pusher.client.Pusher#subscribe(String)} or + * {@link com.pusher.client.Pusher#subscribe(String, ChannelEventListener, String...)} + * again to receive a fresh {@linkplain Channel} instance. + */ + void bind_global(SubscriptionEventListener listener); + /** *

* Unbinds a previously bound {@link SubscriptionEventListener} from an @@ -80,6 +101,36 @@ public interface Channel { */ void unbind(String eventName, SubscriptionEventListener listener); + /** + *

+ * Unbinds a previously bound {@link SubscriptionEventListener} from global + * events. The {@link SubscriptionEventListener} will no longer be notified + * whenever the any event is received on this channel. + *

+ * + *

+ * Calling this method does not unsubscribe from the channel even if there + * are no more {@link SubscriptionEventListener}s bound to it. If you want + * to unsubscribe from the channel completely, call + * {@link com.pusher.client.Pusher#unsubscribe(String)}. It is not necessary + * to unbind your {@link SubscriptionEventListener}s first. + *

+ * + * @param listener + * The listener to unbind from the event. + * @throws IllegalArgumentException + * If the {@link SubscriptionEventListener} is null. + * @throws IllegalStateException + * If the channel has been unsubscribed by calling + * {@link com.pusher.client.Pusher#unsubscribe(String)}. This + * puts the {@linkplain Channel} in a terminal state from which + * it can no longer be used. To resubscribe, call + * {@link com.pusher.client.Pusher#subscribe(String)} or + * {@link com.pusher.client.Pusher#subscribe(String, ChannelEventListener, String...)} + * again to receive a fresh {@linkplain Channel} instance. + */ + void unbind_global(SubscriptionEventListener listener); + /** * * @return Whether or not the channel is subscribed. diff --git a/src/main/java/com/pusher/client/channel/impl/ChannelImpl.java b/src/main/java/com/pusher/client/channel/impl/ChannelImpl.java index b6f41309..54b98efa 100644 --- a/src/main/java/com/pusher/client/channel/impl/ChannelImpl.java +++ b/src/main/java/com/pusher/client/channel/impl/ChannelImpl.java @@ -17,6 +17,7 @@ public class ChannelImpl implements InternalChannel { private static final String INTERNAL_EVENT_PREFIX = "pusher_internal:"; protected static final String SUBSCRIPTION_SUCCESS_EVENT = "pusher_internal:subscription_succeeded"; protected final String name; + private Set globalListners = new HashSet(); private final Map> eventNameToListenerMap = new HashMap>(); protected volatile ChannelState state = ChannelState.INITIAL; private ChannelEventListener eventListener; @@ -66,6 +67,18 @@ public void bind(final String eventName, final SubscriptionEventListener listene } } + @Override + public void bind_global(SubscriptionEventListener listener) { + validateArguments("", listener); + + synchronized(lock) { + if (globalListners == null) { + globalListners = new HashSet(); + } + globalListners.add(listener); + } + } + @Override public void unbind(final String eventName, final SubscriptionEventListener listener) { @@ -82,6 +95,17 @@ public void unbind(final String eventName, final SubscriptionEventListener liste } } + @Override + public void unbind_global(SubscriptionEventListener listener) { + validateArguments("", listener); + + synchronized(lock) { + if (globalListners != null) { + globalListners.remove(listener); + } + } + } + @Override public boolean isSubscribed() { return state == ChannelState.SUBSCRIBED; @@ -220,7 +244,10 @@ protected Set getInterestedListeners(String event) { return null; } - return new HashSet<>(sharedListeners); + return new HashSet(){{ + addAll(sharedListeners); + addAll(globalListners); + }}; } } } From b92020fa159407e0485106a7ecf60dd213a5a172 Mon Sep 17 00:00:00 2001 From: Ashmeet Singh Date: Mon, 15 Nov 2021 18:16:23 +0100 Subject: [PATCH 2/5] Unit Tests --- .../client/channel/impl/ChannelImpl.java | 17 +++++++---- .../client/channel/impl/ChannelImplTest.java | 9 ++++++ .../impl/PrivateEncryptedChannelImplTest.java | 30 +++++++++++++++++++ 3 files changed, 50 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/pusher/client/channel/impl/ChannelImpl.java b/src/main/java/com/pusher/client/channel/impl/ChannelImpl.java index 54b98efa..cb1e19b5 100644 --- a/src/main/java/com/pusher/client/channel/impl/ChannelImpl.java +++ b/src/main/java/com/pusher/client/channel/impl/ChannelImpl.java @@ -236,18 +236,23 @@ private void validateArguments(final String eventName, final SubscriptionEventLi protected Set getInterestedListeners(String event) { synchronized (lock) { - + Set listners = new HashSet(); + final Set sharedListeners = eventNameToListenerMap.get(event); - if (sharedListeners == null) { + if (sharedListeners != null ) { + listners.addAll(sharedListeners); + } + if (!globalListners.isEmpty()) { + listners.addAll(globalListners); + } + + if (listners.isEmpty()){ return null; } - return new HashSet(){{ - addAll(sharedListeners); - addAll(globalListners); - }}; + return listners; } } } diff --git a/src/test/java/com/pusher/client/channel/impl/ChannelImplTest.java b/src/test/java/com/pusher/client/channel/impl/ChannelImplTest.java index 894c2c01..0694f9d2 100644 --- a/src/test/java/com/pusher/client/channel/impl/ChannelImplTest.java +++ b/src/test/java/com/pusher/client/channel/impl/ChannelImplTest.java @@ -120,6 +120,15 @@ public void testDataIsExtractedFromMessageAndPassedToSingleListener() { assertEquals("{\"fish\":\"chips\"}", argCaptor.getValue().getData()); } @Test + public void testDataIsExtractedFromMessageAndPassedToSingleListenerGlobalEvent() { + channel.bind_global(mockListener); + channel.onMessage(EVENT_NAME, "{\"event\":\"event1\",\"data\":\"{\\\"fish\\\":\\\"chips\\\"}\"}"); + + verify(mockListener, times(1)).onEvent(argCaptor.capture()); + assertEquals("event1", argCaptor.getValue().getEventName()); + assertEquals("{\"fish\":\"chips\"}", argCaptor.getValue().getData()); + } + @Test public void testDataIsExtractedFromMessageAndPassedToMultipleListeners() { final ChannelEventListener mockListener2 = getEventListener(); diff --git a/src/test/java/com/pusher/client/channel/impl/PrivateEncryptedChannelImplTest.java b/src/test/java/com/pusher/client/channel/impl/PrivateEncryptedChannelImplTest.java index c11eb6ce..da81aacf 100644 --- a/src/test/java/com/pusher/client/channel/impl/PrivateEncryptedChannelImplTest.java +++ b/src/test/java/com/pusher/client/channel/impl/PrivateEncryptedChannelImplTest.java @@ -190,6 +190,36 @@ public void testDataIsExtractedFromMessageAndPassedToSingleListener() { assertEquals("{\"message\":\"hello world\"}", argCaptor.getValue().getData()); } + @Test + public void testDataIsExtractedFromMessageAndPassedToSingleListenerGlobalEvent() { + PrivateEncryptedChannelImpl channel = new PrivateEncryptedChannelImpl( + mockInternalConnection, + getChannelName(), + mockAuthorizer, + factory, + mockSecretBoxOpenerFactory); + + when(mockAuthorizer.authorize(Matchers.anyString(), Matchers.anyString())) + .thenReturn(AUTH_RESPONSE); + when(mockSecretBoxOpenerFactory.create(any())) + .thenReturn(new SecretBoxOpener(Base64.decode(SHARED_SECRET))); + + channel.toSubscribeMessage(); + + PrivateEncryptedChannelEventListener mockListener = mock(PrivateEncryptedChannelEventListener.class); + + channel.bind_global(mockListener); + + channel.onMessage("my-event", "{\"event\":\"event1\",\"data\":\"{" + + "\\\"nonce\\\": \\\"4sVYwy4j/8dCcjyxtPCWyk19GaaViaW9\\\"," + + "\\\"ciphertext\\\": \\\"/GMESnFGlbNn01BuBjp31XYa3i9vZsGKR8fgR9EDhXKx3lzGiUD501A=\\\"" + + "}\"}"); + + verify(mockListener, times(1)).onEvent(argCaptor.capture()); + assertEquals("event1", argCaptor.getValue().getEventName()); + assertEquals("{\"message\":\"hello world\"}", argCaptor.getValue().getData()); + } + @Test public void testDataIsExtractedFromMessageAndPassedToMultipleListeners() { PrivateEncryptedChannelImpl channel = new PrivateEncryptedChannelImpl( From 0d392f39d5e644865d96701e1f54b6c6f43e76c1 Mon Sep 17 00:00:00 2001 From: Ashmeet Singh Date: Mon, 15 Nov 2021 18:24:37 +0100 Subject: [PATCH 3/5] unbind_global test --- .../com/pusher/client/channel/impl/ChannelImplTest.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/test/java/com/pusher/client/channel/impl/ChannelImplTest.java b/src/test/java/com/pusher/client/channel/impl/ChannelImplTest.java index 0694f9d2..bf922dc2 100644 --- a/src/test/java/com/pusher/client/channel/impl/ChannelImplTest.java +++ b/src/test/java/com/pusher/client/channel/impl/ChannelImplTest.java @@ -163,6 +163,15 @@ public void testEventIsNotPassedOnIfListenerHasUnboundFromEvent() { verify(mockListener, never()).onEvent(any(PusherEvent.class)); } + @Test + public void testEventIsNotPassedOnIfListenerHasUnboundFromGlobalEvent() { + + channel.bind_global(mockListener); + channel.unbind_global(mockListener); + channel.onMessage(EVENT_NAME, "{\"event\":\"event1\",\"data\":\"{\\\"fish\\\":\\\"chips\\\"}\"}"); + + verify(mockListener, never()).onEvent(any(PusherEvent.class)); + } @Test(expected = IllegalArgumentException.class) public void testBindWithNullEventNameThrowsException() { From 9c1f44863d1e8ddc4698d4939738e3e585814d1a Mon Sep 17 00:00:00 2001 From: Ashmeet Singh Date: Tue, 16 Nov 2021 22:03:17 +0100 Subject: [PATCH 4/5] Symatic changes --- .../com/pusher/client/channel/Channel.java | 4 ++-- .../client/channel/impl/ChannelImpl.java | 19 ++++++++----------- .../client/channel/impl/ChannelImplTest.java | 6 +++--- .../impl/PrivateEncryptedChannelImplTest.java | 2 +- 4 files changed, 14 insertions(+), 17 deletions(-) diff --git a/src/main/java/com/pusher/client/channel/Channel.java b/src/main/java/com/pusher/client/channel/Channel.java index 542038e0..90289bed 100644 --- a/src/main/java/com/pusher/client/channel/Channel.java +++ b/src/main/java/com/pusher/client/channel/Channel.java @@ -63,7 +63,7 @@ public interface Channel { * {@link com.pusher.client.Pusher#subscribe(String, ChannelEventListener, String...)} * again to receive a fresh {@linkplain Channel} instance. */ - void bind_global(SubscriptionEventListener listener); + void bindGlobal(SubscriptionEventListener listener); /** *

@@ -129,7 +129,7 @@ public interface Channel { * {@link com.pusher.client.Pusher#subscribe(String, ChannelEventListener, String...)} * again to receive a fresh {@linkplain Channel} instance. */ - void unbind_global(SubscriptionEventListener listener); + void unbindGlobal(SubscriptionEventListener listener); /** * diff --git a/src/main/java/com/pusher/client/channel/impl/ChannelImpl.java b/src/main/java/com/pusher/client/channel/impl/ChannelImpl.java index cb1e19b5..399816ed 100644 --- a/src/main/java/com/pusher/client/channel/impl/ChannelImpl.java +++ b/src/main/java/com/pusher/client/channel/impl/ChannelImpl.java @@ -17,7 +17,7 @@ public class ChannelImpl implements InternalChannel { private static final String INTERNAL_EVENT_PREFIX = "pusher_internal:"; protected static final String SUBSCRIPTION_SUCCESS_EVENT = "pusher_internal:subscription_succeeded"; protected final String name; - private Set globalListners = new HashSet(); + private Set globalListeners = new HashSet(); private final Map> eventNameToListenerMap = new HashMap>(); protected volatile ChannelState state = ChannelState.INITIAL; private ChannelEventListener eventListener; @@ -68,14 +68,11 @@ public void bind(final String eventName, final SubscriptionEventListener listene } @Override - public void bind_global(SubscriptionEventListener listener) { + public void bindGlobal(SubscriptionEventListener listener) { validateArguments("", listener); synchronized(lock) { - if (globalListners == null) { - globalListners = new HashSet(); - } - globalListners.add(listener); + globalListeners.add(listener); } } @@ -96,12 +93,12 @@ public void unbind(final String eventName, final SubscriptionEventListener liste } @Override - public void unbind_global(SubscriptionEventListener listener) { + public void unbindGlobal(SubscriptionEventListener listener) { validateArguments("", listener); synchronized(lock) { - if (globalListners != null) { - globalListners.remove(listener); + if (globalListeners != null) { + globalListeners.remove(listener); } } } @@ -244,8 +241,8 @@ protected Set getInterestedListeners(String event) { if (sharedListeners != null ) { listners.addAll(sharedListeners); } - if (!globalListners.isEmpty()) { - listners.addAll(globalListners); + if (!globalListeners.isEmpty()) { + listners.addAll(globalListeners); } if (listners.isEmpty()){ diff --git a/src/test/java/com/pusher/client/channel/impl/ChannelImplTest.java b/src/test/java/com/pusher/client/channel/impl/ChannelImplTest.java index bf922dc2..5699a4a0 100644 --- a/src/test/java/com/pusher/client/channel/impl/ChannelImplTest.java +++ b/src/test/java/com/pusher/client/channel/impl/ChannelImplTest.java @@ -121,7 +121,7 @@ public void testDataIsExtractedFromMessageAndPassedToSingleListener() { } @Test public void testDataIsExtractedFromMessageAndPassedToSingleListenerGlobalEvent() { - channel.bind_global(mockListener); + channel.bindGlobal(mockListener); channel.onMessage(EVENT_NAME, "{\"event\":\"event1\",\"data\":\"{\\\"fish\\\":\\\"chips\\\"}\"}"); verify(mockListener, times(1)).onEvent(argCaptor.capture()); @@ -166,8 +166,8 @@ public void testEventIsNotPassedOnIfListenerHasUnboundFromEvent() { @Test public void testEventIsNotPassedOnIfListenerHasUnboundFromGlobalEvent() { - channel.bind_global(mockListener); - channel.unbind_global(mockListener); + channel.bindGlobal(mockListener); + channel.unbindGlobal(mockListener); channel.onMessage(EVENT_NAME, "{\"event\":\"event1\",\"data\":\"{\\\"fish\\\":\\\"chips\\\"}\"}"); verify(mockListener, never()).onEvent(any(PusherEvent.class)); diff --git a/src/test/java/com/pusher/client/channel/impl/PrivateEncryptedChannelImplTest.java b/src/test/java/com/pusher/client/channel/impl/PrivateEncryptedChannelImplTest.java index da81aacf..7bcabf8d 100644 --- a/src/test/java/com/pusher/client/channel/impl/PrivateEncryptedChannelImplTest.java +++ b/src/test/java/com/pusher/client/channel/impl/PrivateEncryptedChannelImplTest.java @@ -208,7 +208,7 @@ public void testDataIsExtractedFromMessageAndPassedToSingleListenerGlobalEvent() PrivateEncryptedChannelEventListener mockListener = mock(PrivateEncryptedChannelEventListener.class); - channel.bind_global(mockListener); + channel.bindGlobal(mockListener); channel.onMessage("my-event", "{\"event\":\"event1\",\"data\":\"{" + "\\\"nonce\\\": \\\"4sVYwy4j/8dCcjyxtPCWyk19GaaViaW9\\\"," + From 2414cc97e0b8b447bc8fa3e8c8fadf001dfd52b8 Mon Sep 17 00:00:00 2001 From: Ashmeet Singh Date: Wed, 17 Nov 2021 14:12:42 +0100 Subject: [PATCH 5/5] Spelling error --- .../com/pusher/client/channel/impl/ChannelImpl.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/pusher/client/channel/impl/ChannelImpl.java b/src/main/java/com/pusher/client/channel/impl/ChannelImpl.java index 399816ed..24f8c370 100644 --- a/src/main/java/com/pusher/client/channel/impl/ChannelImpl.java +++ b/src/main/java/com/pusher/client/channel/impl/ChannelImpl.java @@ -233,23 +233,23 @@ private void validateArguments(final String eventName, final SubscriptionEventLi protected Set getInterestedListeners(String event) { synchronized (lock) { - Set listners = new HashSet(); + Set listeners = new HashSet(); final Set sharedListeners = eventNameToListenerMap.get(event); if (sharedListeners != null ) { - listners.addAll(sharedListeners); + listeners.addAll(sharedListeners); } if (!globalListeners.isEmpty()) { - listners.addAll(globalListeners); + listeners.addAll(globalListeners); } - if (listners.isEmpty()){ + if (listeners.isEmpty()){ return null; } - return listners; + return listeners; } } }