This is an automated email from the ASF dual-hosted git repository.

timothyjward pushed a commit to branch feature/v1.1
in repository https://gitbox.apache.org/repos/asf/aries-typedevent.git


The following commit(s) were added to refs/heads/feature/v1.1 by this push:
     new a0c02c9  Fix bug in whiteboard service update/remove
a0c02c9 is described below

commit a0c02c9e8dea7a5aa48e5fc42a89b433df130087
Author: Tim Ward <[email protected]>
AuthorDate: Fri Sep 15 16:05:46 2023 +0100

    Fix bug in whiteboard service update/remove
    
    The removal code did not correctly clear instances from the type specific 
id maps, or from the wildcard maps. This commit adds a test for the failing 
case and also fixes the map management logic.
    
    Signed-off-by: Tim Ward <[email protected]>
---
 .../typedevent/bus/impl/TypedEventBusImpl.java     |  20 ++--
 .../bus/osgi/EventDeliveryIntegrationTest.java     | 101 ++++++++++++++++++++-
 2 files changed, 113 insertions(+), 8 deletions(-)

diff --git 
a/org.apache.aries.typedevent.bus/src/main/java/org/apache/aries/typedevent/bus/impl/TypedEventBusImpl.java
 
b/org.apache.aries.typedevent.bus/src/main/java/org/apache/aries/typedevent/bus/impl/TypedEventBusImpl.java
index e221e2f..5c58047 100644
--- 
a/org.apache.aries.typedevent.bus/src/main/java/org/apache/aries/typedevent/bus/impl/TypedEventBusImpl.java
+++ 
b/org.apache.aries.typedevent.bus/src/main/java/org/apache/aries/typedevent/bus/impl/TypedEventBusImpl.java
@@ -278,7 +278,7 @@ public class TypedEventBusImpl implements TypedEventBus {
                } else {
                        mapToUse = map;
                        topicToUse = s;
-                       selector = new EventSelector(s, f);
+                       selector = new EventSelector(null, f);
                }
                Map<T, EventSelector> handlers = 
mapToUse.computeIfAbsent(topicToUse, x1 -> new HashMap<>());
                handlers.put(handler, selector);
@@ -294,7 +294,7 @@ public class TypedEventBusImpl implements TypedEventBus {
 
         Long serviceId = getServiceId(properties);
 
-        doRemoveEventHandler(topicsToTypedHandlers, knownTypedHandlers, 
handler, serviceId);
+        doRemoveEventHandler(topicsToTypedHandlers, 
wildcardTopicsToTypedHandlers, knownTypedHandlers, handler, serviceId);
 
         synchronized (lock) {
             typedHandlersToTargetClasses.remove(handler);
@@ -305,7 +305,7 @@ public class TypedEventBusImpl implements TypedEventBus {
 
         Long serviceId = getServiceId(properties);
 
-        doRemoveEventHandler(topicsToUntypedHandlers, knownUntypedHandlers, 
handler, serviceId);
+        doRemoveEventHandler(topicsToUntypedHandlers, 
wildcardTopicsToUntypedHandlers, knownUntypedHandlers, handler, serviceId);
     }
 
     private Long getServiceId(Map<String, Object> properties) {
@@ -330,14 +330,20 @@ public class TypedEventBusImpl implements TypedEventBus {
         }
     }
 
-    private <T, U> void doRemoveEventHandler(Map<String, Map<T, U>> map, 
Map<Long, T> idMap, 
+    private <T, U> void doRemoveEventHandler(Map<String, Map<T, U>> map, 
Map<String, Map<T, U>> wildcardMap, Map<Long, T> idMap, 
             T handler, Long serviceId) {
         synchronized (lock) {
             List<String> consumed = knownHandlers.remove(serviceId);
-            knownHandlers.remove(serviceId);
+            idMap.remove(serviceId);
             if (consumed != null) {
                 consumed.forEach(s -> {
-                    Map<T, ?> handlers = map.get(s);
+                       Map<T, ?> handlers;
+                       if(isWildcard(s)) {
+                               handlers = wildcardMap.get(new EventSelector(s, 
null).getInitial());
+                       } else {
+                               handlers = map.get(s);
+                       }
+                       
                     if (handlers != null) {
                         handlers.remove(handler);
                         if (handlers.isEmpty()) {
@@ -373,7 +379,7 @@ public class TypedEventBusImpl implements TypedEventBus {
 
         synchronized (lock) {
             T handler = idToHandler.get(serviceId);
-            doRemoveEventHandler(map, idToHandler, handler, serviceId);
+            doRemoveEventHandler(map, wildcardMap, idToHandler, handler, 
serviceId);
             doAddEventHandler(map, wildcardMap, idToHandler, handler, 
defaultTopic, properties,
                        (a,b) -> new EventTask() {
                                                @Override
diff --git 
a/org.apache.aries.typedevent.bus/src/test/java/org/apache/aries/typedevent/bus/osgi/EventDeliveryIntegrationTest.java
 
b/org.apache.aries.typedevent.bus/src/test/java/org/apache/aries/typedevent/bus/osgi/EventDeliveryIntegrationTest.java
index d435b7a..d77a6a6 100644
--- 
a/org.apache.aries.typedevent.bus/src/test/java/org/apache/aries/typedevent/bus/osgi/EventDeliveryIntegrationTest.java
+++ 
b/org.apache.aries.typedevent.bus/src/test/java/org/apache/aries/typedevent/bus/osgi/EventDeliveryIntegrationTest.java
@@ -18,6 +18,7 @@ package org.apache.aries.typedevent.bus.osgi;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.mockito.ArgumentMatchers.eq;
+import static 
org.osgi.service.typedevent.TypedEventConstants.TYPED_EVENT_TOPICS;
 
 import java.util.Dictionary;
 import java.util.HashMap;
@@ -211,6 +212,104 @@ public class EventDeliveryIntegrationTest extends 
AbstractIntegrationTest {
         assertEquals("foo", received.subEvent.message);
     }
     
-    
+    /**
+     * Tests that events are delivered to untyped Event Handlers
+     * based on topic
+     * 
+     * @throws InterruptedException
+     */
+    @Test
+    public void testEventReceivingUpdateTopic() throws InterruptedException {
+        
+        TestEvent event = new TestEvent();
+        event.message = "boo";
+        
+        Dictionary<String, Object> props = new Hashtable<>();
+        props.put(TYPED_EVENT_TOPICS, TEST_EVENT_TOPIC);
+        
+        regs.add(context.registerService(TypedEventHandler.class, 
typedEventHandler, props));
+
+        regs.add(context.registerService(UntypedEventHandler.class, 
untypedEventHandler, props));
+        
+        eventBus.deliver(event);
+        
+        Mockito.verify(typedEventHandler, Mockito.timeout(1000)).notify(
+                Mockito.eq(TEST_EVENT_TOPIC), 
Mockito.argThat(isTestEventWithMessage("boo")));
+
+        Mockito.verify(untypedEventHandler, 
Mockito.timeout(1000)).notifyUntyped(
+                Mockito.eq(TEST_EVENT_TOPIC), 
Mockito.argThat(isUntypedTestEventWithMessage("boo")));
+        
+        Mockito.clearInvocations(typedEventHandler, untypedEventHandler);
+        
+        props.put(TYPED_EVENT_TOPICS, TEST_EVENT_2_TOPIC);
+        
+        regs.forEach(s -> s.setProperties(props));
+        
+        eventBus.deliver(event);
+        
+        Mockito.verify(typedEventHandler, Mockito.after(1000).never()).notify(
+                Mockito.eq(TEST_EVENT_TOPIC), Mockito.any());
+        Mockito.verify(untypedEventHandler, 
Mockito.after(1000).never()).notifyUntyped(
+                       Mockito.eq(TEST_EVENT_TOPIC), Mockito.any());
+        
+        eventBus.deliver(TEST_EVENT_2_TOPIC, event);
+        
+        Mockito.verify(typedEventHandler, Mockito.timeout(1000)).notify(
+                Mockito.eq(TEST_EVENT_2_TOPIC), 
Mockito.argThat(isTestEventWithMessage("boo")));
+
+        Mockito.verify(untypedEventHandler, 
Mockito.timeout(1000)).notifyUntyped(
+                Mockito.eq(TEST_EVENT_2_TOPIC), 
Mockito.argThat(isUntypedTestEventWithMessage("boo")));
+        
+    }
+
+    /**
+     * Tests that events are delivered to untyped Event Handlers
+     * based on topic
+     * 
+     * @throws InterruptedException
+     */
+    @Test
+    public void testEventReceivingUpdateWildcardTopic() throws 
InterruptedException {
+       
+       TestEvent event = new TestEvent();
+       event.message = "boo";
+       
+       Dictionary<String, Object> props = new Hashtable<>();
+       props.put(TYPED_EVENT_TOPICS, "foo/+/foobar");
+       
+       regs.add(context.registerService(TypedEventHandler.class, 
typedEventHandler, props));
+       
+       regs.add(context.registerService(UntypedEventHandler.class, 
untypedEventHandler, props));
+       
+       eventBus.deliver("foo/bar/foobar", event);
+       
+       Mockito.verify(typedEventHandler, Mockito.timeout(1000)).notify(
+                       Mockito.eq("foo/bar/foobar"), 
Mockito.argThat(isTestEventWithMessage("boo")));
+       
+       Mockito.verify(untypedEventHandler, 
Mockito.timeout(1000)).notifyUntyped(
+                       Mockito.eq("foo/bar/foobar"), 
Mockito.argThat(isUntypedTestEventWithMessage("boo")));
+       
+       Mockito.clearInvocations(typedEventHandler, untypedEventHandler);
+       
+       props.put(TYPED_EVENT_TOPICS, "foo/bar/foobar/+");
+       
+       regs.forEach(s -> s.setProperties(props));
+       
+       eventBus.deliver("foo/bar/foobar", event);
+       
+       Mockito.verify(typedEventHandler, Mockito.after(1000).never()).notify(
+                       Mockito.eq("foo/bar/foobar"), Mockito.any());
+       Mockito.verify(untypedEventHandler, 
Mockito.after(1000).never()).notifyUntyped(
+                       Mockito.eq("foo/bar/foobar"), Mockito.any());
+       
+       eventBus.deliver("foo/bar/foobar/fizzbuzz", event);
+       
+       Mockito.verify(typedEventHandler, Mockito.timeout(1000)).notify(
+                       Mockito.eq("foo/bar/foobar/fizzbuzz"), 
Mockito.argThat(isTestEventWithMessage("boo")));
+       
+       Mockito.verify(untypedEventHandler, 
Mockito.timeout(1000)).notifyUntyped(
+                       Mockito.eq("foo/bar/foobar/fizzbuzz"), 
Mockito.argThat(isUntypedTestEventWithMessage("boo")));
+       
+    }
     
 }
\ No newline at end of file

Reply via email to