package ameba.event; import ameba.container.event.ShutdownEvent; import co.paralleluniverse.actors.behaviors.EventHandler; import co.paralleluniverse.actors.behaviors.EventSource; import co.paralleluniverse.actors.behaviors.EventSourceActor; import co.paralleluniverse.fibers.RuntimeSuspendExecution; import co.paralleluniverse.fibers.SuspendExecution; import com.google.common.collect.Maps; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Map; /** * <p>Abstract AsyncEventBus class.</p> * * @author icode */ public class AsyncEventBus<Event extends ameba.event.Event> implements EventBus<Event> { private static final Logger logger = LoggerFactory.getLogger(AsyncEventBus.class); private final Map<Class<? extends Event>, EventSource<? extends Event>> eventSourceMap = Maps.newConcurrentMap(); @SuppressWarnings("unchecked") protected AsyncEventBus() { subscribe((Class<Event>) ShutdownEvent.class, event -> shutdown()); } public static <Event extends ameba.event.Event> AsyncEventBus<Event> create() { return new AsyncEventBus<>(); } @Override @SuppressWarnings("unchecked") public <E extends Event> void subscribe(Class<E> event, Listener<E> listener) { try { eventSourceMap.computeIfAbsent( event, k -> new EventSourceActor<E>(AsyncEventBus.class.getName()).spawn() ).addHandler(handler(event, listener)); } catch (SuspendExecution e) { throw RuntimeSuspendExecution.of(e); } catch (InterruptedException e) { logger.error("subscribe event has error", e); } } public <E extends Event> void subscribe(Class<E> event, AsyncListener<E> listener) { subscribe(event, (Listener<E>) listener); } @Override @SuppressWarnings("unchecked") public <E extends Event> void unsubscribe(Class<E> event, Listener<E> listener) { EventSource<? extends Event> eventSource = eventSourceMap.get(event); if (eventSource != null) { try { eventSource.removeHandler(handler(event, listener)); } catch (SuspendExecution e) { throw RuntimeSuspendExecution.of(e); } catch (InterruptedException e) { logger.error("unsubscribe event has error", e); } } } @Override public <E extends Event> void unsubscribe(Class<E> event) { EventSource eventSource = eventSourceMap.remove(event); if (eventSource != null) { eventSource.shutdown(); } } @Override @SuppressWarnings("unchecked") public <E extends Event> void publish(E event) { if (event != null) { EventSource<Event> eventSource = (EventSource<Event>) eventSourceMap.get(event.getClass()); if (eventSource != null) { try { eventSource.notify(event); } catch (SuspendExecution e) { throw RuntimeSuspendExecution.of(e); } } } } /** * shutdown event bus */ public void shutdown() { eventSourceMap.values().forEach(EventSource::shutdown); } private <E extends Event> EventHandler handler(Class<E> event, Listener<E> listener) { return new Handler<>(event, listener); } private class Handler<E extends ameba.event.Event> implements EventHandler<E> { private Class<E> event; private Listener<E> listener; Handler(Class<E> event, Listener<E> listener) { this.event = event; this.listener = listener; } @Override public void handleEvent(E event) throws SuspendExecution, InterruptedException { listener.onReceive(event); } @Override @SuppressWarnings("unchecked") public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Handler handler = (Handler) o; if (event != null ? !event.equals(handler.event) : handler.event != null) return false; return listener != null ? listener.equals(handler.listener) : handler.listener == null; } @Override public int hashCode() { int result = event != null ? event.hashCode() : 0; result = 31 * result + (listener != null ? listener.hashCode() : 0); return result; } } }