Add an event bus (#10)
diff --git a/server/core/src/main/java/org/apache/vysper/event/EventBus.java b/server/core/src/main/java/org/apache/vysper/event/EventBus.java
new file mode 100644
index 0000000..003e695
--- /dev/null
+++ b/server/core/src/main/java/org/apache/vysper/event/EventBus.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.vysper.event;
+
+/**
+ * @author Réda Housni Alaoui
+ */
+public interface EventBus {
+
+ /**
+ * Publishes an event.
+ */
+ <T> EventBus publish(Class<T> eventType, T event);
+
+}
diff --git a/server/core/src/main/java/org/apache/vysper/event/EventListener.java b/server/core/src/main/java/org/apache/vysper/event/EventListener.java
new file mode 100644
index 0000000..14927f0
--- /dev/null
+++ b/server/core/src/main/java/org/apache/vysper/event/EventListener.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.vysper.event;
+
+/**
+ * @author Réda Housni Alaoui
+ */
+public interface EventListener<T> {
+
+ /**
+ * Called when an event is to be handled by this listener. Any exception thrown
+ * by this method will be swiftly trapped. This method cannot and should not try
+ * to stop/alter the workflow that produced the event.
+ */
+ void onEvent(T event);
+
+}
diff --git a/server/core/src/main/java/org/apache/vysper/event/EventListenerDictionary.java b/server/core/src/main/java/org/apache/vysper/event/EventListenerDictionary.java
new file mode 100644
index 0000000..32e6602
--- /dev/null
+++ b/server/core/src/main/java/org/apache/vysper/event/EventListenerDictionary.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.vysper.event;
+
+import java.util.Set;
+
+/**
+ * @author Réda Housni Alaoui
+ */
+public interface EventListenerDictionary {
+
+ /**
+ * @return The listeners registered for the provided event type.
+ */
+ Set<EventListener<?>> get(Class<?> eventType);
+
+}
diff --git a/server/core/src/main/java/org/apache/vysper/event/SimpleEventBus.java b/server/core/src/main/java/org/apache/vysper/event/SimpleEventBus.java
new file mode 100644
index 0000000..74ed21c
--- /dev/null
+++ b/server/core/src/main/java/org/apache/vysper/event/SimpleEventBus.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.vysper.event;
+
+import java.util.Collection;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author Réda Housni Alaoui
+ */
+public class SimpleEventBus implements EventBus {
+
+ private static final Logger LOG = LoggerFactory.getLogger(SimpleEventBus.class);
+
+ private final Set<EventListenerDictionary> listenerDictionaries = new LinkedHashSet<>();
+
+ public SimpleEventBus addDictionary(EventListenerDictionary dictionary) {
+ listenerDictionaries.add(dictionary);
+ return this;
+ }
+
+ @Override
+ public <T> EventBus publish(Class<T> eventType, T event) {
+ listenerDictionaries.stream().map(eventListenerDictionary -> eventListenerDictionary.get(eventType))
+ .flatMap(Collection::stream).distinct().forEach(listener -> fireEvent(event, listener));
+ return this;
+ }
+
+ @SuppressWarnings("unchecked")
+ private <T> void fireEvent(T event, EventListener<?> listener) {
+ LOG.trace("Firing event {} on listener {}", event, listener);
+ try {
+ ((EventListener<T>) listener).onEvent(event);
+ LOG.trace("Fired event {} on listener {}", event, listener);
+ } catch (Exception e) {
+ LOG.error(e.getMessage(), e);
+ }
+ }
+
+}
diff --git a/server/core/src/main/java/org/apache/vysper/event/SimpleEventListenerDictionary.java b/server/core/src/main/java/org/apache/vysper/event/SimpleEventListenerDictionary.java
new file mode 100644
index 0000000..3402b60
--- /dev/null
+++ b/server/core/src/main/java/org/apache/vysper/event/SimpleEventListenerDictionary.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.vysper.event;
+
+import static java.util.Optional.ofNullable;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @author Réda Housni Alaoui
+ */
+public class SimpleEventListenerDictionary implements EventListenerDictionary {
+
+ private final Map<Class<?>, Set<EventListener<?>>> listenersByEventType;
+
+ private SimpleEventListenerDictionary(Map<Class<?>, Set<EventListener<?>>> listenersByEventType) {
+ this.listenersByEventType = new HashMap<>(listenersByEventType);
+ }
+
+ @Override
+ public Set<EventListener<?>> get(Class<?> eventType) {
+ return ofNullable(listenersByEventType.get(eventType)).orElse(Collections.emptySet());
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+ private final Map<Class<?>, Set<EventListener<?>>> listenersByEventType = new HashMap<>();
+
+ private Builder() {
+ }
+
+ /**
+ * Register the provided listener to the provided event type. Since the listener
+ * reference will never be released, be aware of possible memory leak.
+ */
+ public <T> Builder register(Class<T> eventType, EventListener<T> listener) {
+ listenersByEventType.computeIfAbsent(eventType, type -> new LinkedHashSet<>()).add(listener);
+ return this;
+ }
+
+ public SimpleEventListenerDictionary build() {
+ return new SimpleEventListenerDictionary(listenersByEventType);
+ }
+ }
+
+}
diff --git a/server/core/src/main/java/org/apache/vysper/xmpp/modules/DefaultModule.java b/server/core/src/main/java/org/apache/vysper/xmpp/modules/DefaultModule.java
index 05f6457..e8c2e4b 100644
--- a/server/core/src/main/java/org/apache/vysper/xmpp/modules/DefaultModule.java
+++ b/server/core/src/main/java/org/apache/vysper/xmpp/modules/DefaultModule.java
@@ -21,7 +21,9 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.Optional;
+import org.apache.vysper.event.EventListenerDictionary;
import org.apache.vysper.xmpp.protocol.HandlerDictionary;
import org.apache.vysper.xmpp.server.ServerRuntimeContext;
@@ -46,6 +48,11 @@
// empty default implementation
}
+ @Override
+ public Optional<EventListenerDictionary> getEventListenerDictionary() {
+ return Optional.empty();
+ }
+
public List<ServerRuntimeContextService> getServerServices() {
List<ServerRuntimeContextService> serviceList = new ArrayList<ServerRuntimeContextService>();
addServerServices(serviceList);
diff --git a/server/core/src/main/java/org/apache/vysper/xmpp/modules/Module.java b/server/core/src/main/java/org/apache/vysper/xmpp/modules/Module.java
index e1fee0f..2a9ef08 100644
--- a/server/core/src/main/java/org/apache/vysper/xmpp/modules/Module.java
+++ b/server/core/src/main/java/org/apache/vysper/xmpp/modules/Module.java
@@ -20,7 +20,9 @@
package org.apache.vysper.xmpp.modules;
import java.util.List;
+import java.util.Optional;
+import org.apache.vysper.event.EventListenerDictionary;
import org.apache.vysper.xmpp.protocol.HandlerDictionary;
import org.apache.vysper.xmpp.server.ServerRuntimeContext;
import org.apache.vysper.xmpp.server.XMPPServer;
@@ -33,6 +35,8 @@
* <li>doing initializations, for example adding request listeners to the ServiceDiscoveryRequestListenerRegistry</li>
* <li>adding dictionaries with new stanza handlers getting registered with the server which then get called as
* matching stanzas arrive</li>
+ * <li>adding dictionaries with new event listeners getting registered with the server which then get called as
+ * matching events are published</li>
* </ul>
*
* TODO: think about returning the supported XEPs
@@ -41,6 +45,7 @@
* @see org.apache.vysper.xmpp.modules.DefaultDiscoAwareModule recommended for modules responding to service disco requests
* @see org.apache.vysper.xmpp.modules.ServerRuntimeContextService
* @see org.apache.vysper.xmpp.protocol.HandlerDictionary
+ * @see EventListenerDictionary
*
* @author The Apache MINA Project (dev@mina.apache.org)
*/
@@ -51,11 +56,16 @@
String getVersion();
/**
- * all dictionaries to be added to the server
+ * all stanza handler dictionaries to be added to the server
*/
List<HandlerDictionary> getHandlerDictionaries();
/**
+ * @return The event listener dictionary to be added to the server
+ */
+ Optional<EventListenerDictionary> getEventListenerDictionary();
+
+ /**
* all objects to be added to the server runtime context
*/
List<ServerRuntimeContextService> getServerServices();
diff --git a/server/core/src/main/java/org/apache/vysper/xmpp/server/DefaultServerRuntimeContext.java b/server/core/src/main/java/org/apache/vysper/xmpp/server/DefaultServerRuntimeContext.java
index fde5102..439a6c3 100644
--- a/server/core/src/main/java/org/apache/vysper/xmpp/server/DefaultServerRuntimeContext.java
+++ b/server/core/src/main/java/org/apache/vysper/xmpp/server/DefaultServerRuntimeContext.java
@@ -28,6 +28,8 @@
import javax.net.ssl.SSLContext;
+import org.apache.vysper.event.EventBus;
+import org.apache.vysper.event.SimpleEventBus;
import org.apache.vysper.storage.OpenStorageProviderRegistry;
import org.apache.vysper.storage.StorageProvider;
import org.apache.vysper.storage.StorageProviderRegistry;
@@ -63,7 +65,7 @@
*/
public class DefaultServerRuntimeContext implements ServerRuntimeContext, ModuleRegistry {
- final Logger logger = LoggerFactory.getLogger(DefaultServerRuntimeContext.class);
+ private final Logger logger = LoggerFactory.getLogger(DefaultServerRuntimeContext.class);
// basic internal data structures and configuration...
@@ -124,7 +126,7 @@
/**
* collection of all other services, which are mostly add-ons to the minimal setup
*/
- final private Map<String, ServerRuntimeContextService> serverRuntimeContextServiceMap = new HashMap<String, ServerRuntimeContextService>();
+ private final Map<String, ServerRuntimeContextService> serverRuntimeContextServiceMap = new HashMap<String, ServerRuntimeContextService>();
private List<Module> modules = new ArrayList<Module>();
@@ -132,12 +134,15 @@
* map of all registered components, index by the subdomain they are registered for
*/
protected final Map<String, Component> componentMap = new HashMap<String, Component>();
+
+ private final SimpleEventBus eventBus;
public DefaultServerRuntimeContext(Entity serverEntity, StanzaRelay stanzaRelay) {
this.serverEntity = serverEntity;
this.stanzaRelay = stanzaRelay;
this.resourceRegistry = new DefaultResourceRegistry();
this.stanzaHandlerLookup = new StanzaHandlerLookup(this);
+ this.eventBus = new SimpleEventBus();
}
public DefaultServerRuntimeContext(Entity serverEntity, StanzaRelay stanzaRelay,
@@ -304,7 +309,7 @@
* XMPP extension ('XEP') to it.
* @see org.apache.vysper.xmpp.modules.Module
* @see DefaultServerRuntimeContext#addModules(java.util.List) for adding a number of modules at once
- * @param modules
+ * @param module
*/
public void addModule(Module module) {
addModuleInternal(module);
@@ -337,6 +342,8 @@
}
+ module.getEventListenerDictionary().ifPresent(eventBus::addDictionary);
+
if (module instanceof Component) {
registerComponent((Component) module);
}
@@ -354,7 +361,12 @@
}
return null;
}
-
+
+ @Override
+ public EventBus getEventBus() {
+ return eventBus;
+ }
+
public void registerComponent(Component component) {
componentMap.put(component.getSubdomain(), component);
}
diff --git a/server/core/src/main/java/org/apache/vysper/xmpp/server/ServerRuntimeContext.java b/server/core/src/main/java/org/apache/vysper/xmpp/server/ServerRuntimeContext.java
index 0972ab4..88ebbb3 100644
--- a/server/core/src/main/java/org/apache/vysper/xmpp/server/ServerRuntimeContext.java
+++ b/server/core/src/main/java/org/apache/vysper/xmpp/server/ServerRuntimeContext.java
@@ -24,6 +24,7 @@
import javax.net.ssl.SSLContext;
+import org.apache.vysper.event.EventBus;
import org.apache.vysper.storage.StorageProvider;
import org.apache.vysper.xmpp.addressing.Entity;
import org.apache.vysper.xmpp.authentication.UserAuthentication;
@@ -83,4 +84,6 @@
<T> T getModule(Class<T> clazz);
void addModule(Module module);
+
+ EventBus getEventBus();
}
diff --git a/server/core/src/test/java/org/apache/vysper/event/EventListenerMock.java b/server/core/src/test/java/org/apache/vysper/event/EventListenerMock.java
new file mode 100644
index 0000000..7fd2d9c
--- /dev/null
+++ b/server/core/src/test/java/org/apache/vysper/event/EventListenerMock.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.vysper.event;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import junit.framework.Assert;
+
+/**
+ * @author Réda Housni Alaoui
+ */
+public class EventListenerMock<T> implements EventListener<T> {
+
+ private final List<T> receivedEventsSequence = new ArrayList<>();
+
+ private boolean failOnReceivedEvent;
+
+ public EventListenerMock<T> failOnReceivedEvent() {
+ failOnReceivedEvent = true;
+ return this;
+ }
+
+ public void assertReceivedEventsSequence(T... events) {
+ Assert.assertEquals(Arrays.asList(events), receivedEventsSequence);
+ }
+
+ public void assertNoEventReceived() {
+ Assert.assertTrue(receivedEventsSequence.isEmpty());
+ }
+
+ @Override
+ public void onEvent(T event) {
+ receivedEventsSequence.add(event);
+ if (failOnReceivedEvent) {
+ throw new RuntimeException("Failing as asked");
+ }
+ }
+}
diff --git a/server/core/src/test/java/org/apache/vysper/event/SimpleEventBusTest.java b/server/core/src/test/java/org/apache/vysper/event/SimpleEventBusTest.java
new file mode 100644
index 0000000..0c0f93d
--- /dev/null
+++ b/server/core/src/test/java/org/apache/vysper/event/SimpleEventBusTest.java
@@ -0,0 +1,140 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.vysper.event;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @author Réda Housni Alaoui
+ */
+public class SimpleEventBusTest {
+
+ private EventListenerMock<FooEvent> fooListener;
+
+ private EventListenerMock<BarEvent> barListener;
+
+ private EventListenerMock<BazEvent> bazListener;
+
+ private SimpleEventBus tested;
+
+ @Before
+ public void before() {
+ tested = new SimpleEventBus();
+
+ fooListener = new EventListenerMock<>();
+ barListener = new EventListenerMock<>();
+ bazListener = new EventListenerMock<>();
+ }
+
+ @Test
+ public void publishEventGivenOneDictionary() {
+ tested.addDictionary(SimpleEventListenerDictionary.builder().register(FooEvent.class, fooListener)
+ .register(BarEvent.class, barListener).register(BazEvent.class, bazListener).build());
+
+ FooEvent fooEvent = new FooEvent();
+ tested.publish(FooEvent.class, fooEvent);
+ BarEvent barEvent = new BarEvent();
+ tested.publish(BarEvent.class, barEvent);
+ BazEvent bazEvent = new BazEvent();
+ tested.publish(BazEvent.class, bazEvent);
+
+ fooListener.assertReceivedEventsSequence(fooEvent);
+ barListener.assertReceivedEventsSequence(barEvent);
+ bazListener.assertReceivedEventsSequence(bazEvent);
+ }
+
+ @Test
+ public void publishEventGivenTwoDictionaries() {
+ tested.addDictionary(SimpleEventListenerDictionary.builder().register(FooEvent.class, fooListener)
+ .register(BarEvent.class, barListener).build())
+ .addDictionary(SimpleEventListenerDictionary.builder().register(BazEvent.class, bazListener).build());
+
+ FooEvent fooEvent = new FooEvent();
+ tested.publish(FooEvent.class, fooEvent);
+ BarEvent barEvent = new BarEvent();
+ tested.publish(BarEvent.class, barEvent);
+ BazEvent bazEvent = new BazEvent();
+ tested.publish(BazEvent.class, bazEvent);
+
+ fooListener.assertReceivedEventsSequence(fooEvent);
+ barListener.assertReceivedEventsSequence(barEvent);
+ bazListener.assertReceivedEventsSequence(bazEvent);
+ }
+
+ @Test
+ public void publishEventGivenListenerRegisteredTwiceInOneDictionary() {
+ tested.addDictionary(SimpleEventListenerDictionary.builder().register(FooEvent.class, fooListener)
+ .register(FooEvent.class, fooListener).build());
+
+ FooEvent fooEvent = new FooEvent();
+ tested.publish(FooEvent.class, fooEvent);
+ fooListener.assertReceivedEventsSequence(fooEvent);
+ }
+
+ @Test
+ public void publishEventGivenListenerRegisteredTwiceInTwoDifferentDictionary() {
+ tested.addDictionary(SimpleEventListenerDictionary.builder().register(FooEvent.class, fooListener).build())
+ .addDictionary(SimpleEventListenerDictionary.builder().register(FooEvent.class, fooListener).build());
+
+ FooEvent event = new FooEvent();
+ tested.publish(FooEvent.class, event);
+ fooListener.assertReceivedEventsSequence(event);
+ }
+
+ @Test
+ public void publishSubClassEvent() {
+ tested.addDictionary(SimpleEventListenerDictionary.builder().register(FooEvent.class, fooListener).build());
+
+ SubFooEvent event = new SubFooEvent();
+ tested.publish(FooEvent.class, event);
+ fooListener.assertReceivedEventsSequence(event);
+ }
+
+ @Test
+ public void publishOnTwoListenersGivenOneFailingListener() {
+ EventListenerMock<FooEvent> failingListener = new EventListenerMock<FooEvent>().failOnReceivedEvent();
+ tested.addDictionary(SimpleEventListenerDictionary.builder().register(FooEvent.class, failingListener)
+ .register(FooEvent.class, fooListener).build());
+
+ FooEvent event = new FooEvent();
+ tested.publish(FooEvent.class, event);
+
+ failingListener.assertReceivedEventsSequence(event);
+ fooListener.assertReceivedEventsSequence(event);
+ }
+
+ private static class FooEvent {
+
+ }
+
+ private static class BarEvent {
+
+ }
+
+ private static class BazEvent {
+
+ }
+
+ private static class SubFooEvent extends FooEvent {
+
+ }
+
+}
\ No newline at end of file
diff --git a/server/core/src/test/java/org/apache/vysper/xmpp/server/DefaultServerRuntimeContextEventListenerTest.java b/server/core/src/test/java/org/apache/vysper/xmpp/server/DefaultServerRuntimeContextEventListenerTest.java
new file mode 100644
index 0000000..2e2f520
--- /dev/null
+++ b/server/core/src/test/java/org/apache/vysper/xmpp/server/DefaultServerRuntimeContextEventListenerTest.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.vysper.xmpp.server;
+
+import java.util.Optional;
+
+import org.apache.vysper.event.EventListenerDictionary;
+import org.apache.vysper.event.EventListenerMock;
+import org.apache.vysper.event.SimpleEventListenerDictionary;
+import org.apache.vysper.xmpp.modules.DefaultModule;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @author Réda Housni Alaoui
+ */
+public class DefaultServerRuntimeContextEventListenerTest {
+
+ private EventListenerMock<Event> eventListener;
+
+ private DefaultServerRuntimeContext tested;
+
+ @Before
+ public void before() {
+ eventListener = new EventListenerMock<>();
+ EventListenerDictionary listenerDictionary = SimpleEventListenerDictionary.builder()
+ .register(Event.class, eventListener).build();
+
+ tested = new DefaultServerRuntimeContext(null, null);
+ tested.addModule(new MyModule(listenerDictionary));
+ }
+
+ @Test
+ public void publishEventGivenRegisteredModule() {
+ Event event = new Event();
+ tested.getEventBus().publish(Event.class, event);
+ eventListener.assertReceivedEventsSequence(event);
+ }
+
+ private static class Event {
+
+ }
+
+ private static class MyModule extends DefaultModule {
+
+ private final EventListenerDictionary eventListenerDictionary;
+
+ private MyModule(EventListenerDictionary eventListenerDictionary) {
+ this.eventListenerDictionary = eventListenerDictionary;
+ }
+
+ @Override
+ public String getName() {
+ return "MyModule";
+ }
+
+ @Override
+ public String getVersion() {
+ return "1.0";
+ }
+
+ @Override
+ public Optional<EventListenerDictionary> getEventListenerDictionary() {
+ return Optional.of(eventListenerDictionary);
+ }
+ }
+}
\ No newline at end of file