21.04.2021


EventBus - Example


EventBus.java


package com.sowas.eventbus;

import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Simple event bus implementation.
 * Subscribe for and fire events.
 */
public enum EventBus {
   	INSTANCE;
   	
   	private final Map> subscribers = new ConcurrentHashMap<>();
   	
   	/**
   	 * Subscribe to an event type
   	 *
   	 * @param subscriber The subscriber which will consume the events.
   	 * @param eventClass The event class, can be a super class of Event.
   	 */
   	public void subscribe(ISubscriber subscriber, Class eventClass) {
   	    Objects.requireNonNull(subscriber, "subscriber");
   	    Objects.requireNonNull(eventClass, "eventClass");
   	
   	    subscribers.put(subscriber, eventClass);
   	}
   	
   	/**
   	 * Unsubscribe from all event types.
   	 *
   	 * @param subscriber the subscriber to unsubscribe.
   	 */
   	public void unsubscribe(ISubscriber subscriber) {
   	    Objects.requireNonNull(subscriber, "subscriber");
   	
   	    subscribers.remove(subscriber);
   	}
   	
   	/**
   	 * Publish an event to all subscribers for exactly this event type.
   	 *
   	 * @param event the event.
   	 */
   	public void fire(Event event) {
   	    subscribers.forEach((s, e) -> {
   	    	Class clazz;
   		try {
   			clazz = Class.forName(e.getName());
   		} catch (ClassNotFoundException ex) {
   			ex.printStackTrace();
   			return;
   		}
   	        if (clazz.isInstance(event)) {
   	    		s.handleEventfired(event);
   	    	}
   	    });
   	}
}

ISubscriber.java


package com.sowas.eventbus;

public interface ISubscriber {
   public void handleEventfired(Event event);
}

Event.java


package com.sowas.eventbus;

public class Event {
	private Object data;

	public Object getData() {
		return data;
	}

	public Event(Object data) {
		this.data = data;
	}
}

EventBusTest.java


package com.sowas.eventbus;

import static org.junit.Assert.assertEquals;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

/**
 * Test class for the EventBus.
 */
public class EventBusTest {
	int receivedEventsCount;

	/**
	 * Tests the subscribing for Event.
	 * All(!) Events should be handled.
	 */
	@Test
	public void testSubscribeEvent() {
		ISubscriber subscriber = new ISubscriber() {			
			@Override
			public void handleEventfired(Event event) {
				receivedEventsCount++;
			}
		};
		EventBus.INSTANCE.subscribe(subscriber, Event.class);
		receivedEventsCount = 0;
		EventBus.INSTANCE.fire(new Event(null));
		EventBus.INSTANCE.fire(new ExtendedEvent(null));
		assertEquals(2, receivedEventsCount);
		EventBus.INSTANCE.unsubscribe(subscriber);
	}

	/**
	 * Tests the subscribing for Event.
	 * Only ExtendedEvents should be handled.
	 */
	@Test
	public void testSubscribeDummyEvent() {
		ISubscriber subscriber = new ISubscriber() {			
			@Override
			public void handleEventfired(Event event) {
				receivedEventsCount++;
			}
		};
		EventBus.INSTANCE.subscribe(subscriber, ExtendedEvent.class);
		receivedEventsCount = 0;
		EventBus.INSTANCE.fire(new Event(null));
		EventBus.INSTANCE.fire(new ExtendedEvent(null));
		assertEquals(1, receivedEventsCount);
		EventBus.INSTANCE.unsubscribe(subscriber);
	}

	/**
	 * An Event extended from Event.
	 */
	class ExtendedEvent extends Event {
		public ExtendedEvent(Object data) {
			super(data);
		}
	}
}