add event listener and future completion to generic event manager
This commit is contained in:
parent
3145720f40
commit
ef0a26bbd1
42 changed files with 1424 additions and 1253 deletions
|
@ -1,5 +1,5 @@
|
|||
group = org.xbib
|
||||
name = event
|
||||
version = 0.0.7
|
||||
version = 0.0.8
|
||||
|
||||
org.gradle.warning.mode = ALL
|
||||
|
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
|
@ -1,6 +1,6 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-all.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
|
|
@ -15,11 +15,10 @@ pluginManagement {
|
|||
dependencyResolutionManagement {
|
||||
versionCatalogs {
|
||||
libs {
|
||||
version('gradle', '8.4')
|
||||
version('groovy', '4.0.13')
|
||||
version('gradle', '8.5')
|
||||
version('datastructures', '5.0.5')
|
||||
version('netty', '4.1.100.Final')
|
||||
version('net', '4.0.0')
|
||||
version('netty', '4.1.101.Final')
|
||||
version('net', '4.0.2')
|
||||
library('netty-handler', 'io.netty', 'netty-handler').versionRef('netty')
|
||||
library('net', 'org.xbib', 'net').versionRef('net')
|
||||
library('datastructures-common', 'org.xbib', 'datastructures-common').versionRef('datastructures')
|
||||
|
|
|
@ -34,6 +34,7 @@ public abstract class CompleteFuture<V> extends AbstractFuture<V> {
|
|||
return this;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Future<V> addListeners(GenericFutureListener<? extends Future<? super V>>... listeners) {
|
||||
for (GenericFutureListener<? extends Future<? super V>> l:
|
||||
|
@ -53,6 +54,7 @@ public abstract class CompleteFuture<V> extends AbstractFuture<V> {
|
|||
return this;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Future<V> removeListeners(GenericFutureListener<? extends Future<? super V>>... listeners) {
|
||||
// NOOP
|
||||
|
|
|
@ -9,8 +9,7 @@ final class DefaultFutureListeners {
|
|||
private int progressiveSize; // the number of progressive listeners
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
DefaultFutureListeners(
|
||||
GenericFutureListener<? extends Future<?>> first, GenericFutureListener<? extends Future<?>> second) {
|
||||
DefaultFutureListeners(GenericFutureListener<? extends Future<?>> first, GenericFutureListener<? extends Future<?>> second) {
|
||||
listeners = new GenericFutureListener[2];
|
||||
listeners[0] = first;
|
||||
listeners[1] = second;
|
||||
|
|
|
@ -60,6 +60,7 @@ public class DefaultProgressivePromise<V> extends DefaultPromise<V> implements P
|
|||
return this;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public ProgressivePromise<V> addListeners(GenericFutureListener<? extends Future<? super V>>... listeners) {
|
||||
super.addListeners(listeners);
|
||||
|
@ -72,6 +73,7 @@ public class DefaultProgressivePromise<V> extends DefaultPromise<V> implements P
|
|||
return this;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public ProgressivePromise<V> removeListeners(GenericFutureListener<? extends Future<? super V>>... listeners) {
|
||||
super.removeListeners(listeners);
|
||||
|
|
|
@ -170,6 +170,7 @@ public class DefaultPromise<V> extends AbstractFuture<V> implements Promise<V> {
|
|||
return this;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Promise<V> addListeners(GenericFutureListener<? extends Future<? super V>>... listeners) {
|
||||
Objects.requireNonNull(listeners, "listeners");
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
package org.xbib.event;
|
||||
|
||||
import java.io.Closeable;
|
||||
|
||||
public interface EventConsumer extends Closeable {
|
||||
public interface EventConsumer {
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ import java.util.concurrent.Executors;
|
|||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public final class EventManager implements Closeable {
|
||||
public final class EventManager {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(EventManager.class.getName());
|
||||
|
||||
|
@ -79,17 +79,12 @@ public final class EventManager implements Closeable {
|
|||
return syslogEventManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return super.equals(obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
for (EventConsumer eventConsumer : builder.eventConsumers) {
|
||||
eventConsumer.close();
|
||||
if (eventConsumer instanceof Closeable closeable) {
|
||||
closeable.close();
|
||||
}
|
||||
}
|
||||
genericEventManager.close();
|
||||
clockEventManager.close();
|
||||
timerEventManager.close();
|
||||
fileFollowEventManager.close();
|
||||
|
|
|
@ -11,10 +11,12 @@ public interface Future<V> extends java.util.concurrent.Future<V> {
|
|||
|
||||
Future<V> addListener(GenericFutureListener<? extends Future<? super V>> var1);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Future<V> addListeners(GenericFutureListener<? extends Future<? super V>>... var1);
|
||||
|
||||
Future<V> removeListener(GenericFutureListener<? extends Future<? super V>> var1);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Future<V> removeListeners(GenericFutureListener<? extends Future<? super V>>... var1);
|
||||
|
||||
Future<V> sync() throws InterruptedException;
|
||||
|
|
|
@ -8,12 +8,14 @@ public interface ProgressiveFuture<V> extends Future<V> {
|
|||
@Override
|
||||
ProgressiveFuture<V> addListener(GenericFutureListener<? extends Future<? super V>> listener);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
ProgressiveFuture<V> addListeners(GenericFutureListener<? extends Future<? super V>>... listeners);
|
||||
|
||||
@Override
|
||||
ProgressiveFuture<V> removeListener(GenericFutureListener<? extends Future<? super V>> listener);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
ProgressiveFuture<V> removeListeners(GenericFutureListener<? extends Future<? super V>>... listeners);
|
||||
|
||||
|
|
|
@ -27,12 +27,14 @@ public interface ProgressivePromise<V> extends Promise<V>, ProgressiveFuture<V>
|
|||
@Override
|
||||
ProgressivePromise<V> addListener(GenericFutureListener<? extends Future<? super V>> listener);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
ProgressivePromise<V> addListeners(GenericFutureListener<? extends Future<? super V>>... listeners);
|
||||
|
||||
@Override
|
||||
ProgressivePromise<V> removeListener(GenericFutureListener<? extends Future<? super V>> listener);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
ProgressivePromise<V> removeListeners(GenericFutureListener<? extends Future<? super V>>... listeners);
|
||||
|
||||
|
|
|
@ -13,10 +13,12 @@ public interface Promise<V> extends Future<V> {
|
|||
|
||||
Promise<V> addListener(GenericFutureListener<? extends Future<? super V>> value);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Promise<V> addListeners(GenericFutureListener<? extends Future<? super V>>... value);
|
||||
|
||||
Promise<V> removeListener(GenericFutureListener<? extends Future<? super V>> value);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Promise<V> removeListeners(GenericFutureListener<? extends Future<? super V>>... value);
|
||||
|
||||
Promise<V> await() throws InterruptedException;
|
||||
|
|
|
@ -59,7 +59,7 @@ public interface CompositeFuture extends Future<CompositeFuture> {
|
|||
*
|
||||
* When the list is empty, the returned future will be already completed.
|
||||
*/
|
||||
static CompositeFuture all(List<Future> futures) {
|
||||
static CompositeFuture all(List<Future<?>> futures) {
|
||||
return CompositeFutureImpl.all(futures.toArray(new Future[0]));
|
||||
}
|
||||
|
||||
|
@ -109,7 +109,7 @@ public interface CompositeFuture extends Future<CompositeFuture> {
|
|||
*
|
||||
* When the list is empty, the returned future will be already completed.
|
||||
*/
|
||||
static CompositeFuture any(List<Future> futures) {
|
||||
static CompositeFuture any(List<Future<?>> futures) {
|
||||
return CompositeFutureImpl.any(futures.toArray(new Future[0]));
|
||||
}
|
||||
|
||||
|
@ -159,7 +159,7 @@ public interface CompositeFuture extends Future<CompositeFuture> {
|
|||
*
|
||||
* When the list is empty, the returned future will be already completed.
|
||||
*/
|
||||
static CompositeFuture join(List<Future> futures) {
|
||||
static CompositeFuture join(List<Future<?>> futures) {
|
||||
return CompositeFutureImpl.join(futures.toArray(new Future[0]));
|
||||
}
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ public interface Future<T> extends AsyncResult<T> {
|
|||
* @param <T> the result type
|
||||
* @return the future
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
static <T> Future<T> succeededFuture() {
|
||||
return (Future<T>) SucceededFuture.EMPTY;
|
||||
}
|
||||
|
|
|
@ -100,7 +100,7 @@ public class CompositeFutureImpl extends FutureImpl<CompositeFuture> implements
|
|||
return composite;
|
||||
}
|
||||
|
||||
private final Future[] results;
|
||||
private final Future<?>[] results;
|
||||
private int count;
|
||||
|
||||
private CompositeFutureImpl(Future<?>... results) {
|
||||
|
@ -132,6 +132,7 @@ public class CompositeFutureImpl extends FutureImpl<CompositeFuture> implements
|
|||
return this.<T>future(index).result();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> Future<T> future(int index) {
|
||||
if (index < 0 || index >= results.length) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
|
@ -148,10 +149,6 @@ public class CompositeFutureImpl extends FutureImpl<CompositeFuture> implements
|
|||
tryComplete(this);
|
||||
}
|
||||
|
||||
private void fail(Throwable t) {
|
||||
complete(t);
|
||||
}
|
||||
|
||||
private void complete(Object result) {
|
||||
if (result == this) {
|
||||
tryComplete(this);
|
||||
|
|
|
@ -53,6 +53,7 @@ public final class FailedFuture<T> extends FutureBase<T> {
|
|||
return true;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Future<T> onComplete(Handler<AsyncResult<T>> handler) {
|
||||
if (handler instanceof Listener) {
|
||||
|
@ -105,11 +106,13 @@ public final class FailedFuture<T> extends FutureBase<T> {
|
|||
return true;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <U> Future<U> map(Function<T, U> mapper) {
|
||||
return (Future<U>) this;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <V> Future<V> map(V value) {
|
||||
return (Future<V>) this;
|
||||
|
|
|
@ -36,6 +36,7 @@ class FutureImpl<T> extends FutureBase<T> {
|
|||
/**
|
||||
* The result of the operation. This will be null if the operation failed.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public synchronized T result() {
|
||||
return value instanceof CauseHolder ? null : value == NULL_VALUE ? null : (T) value;
|
||||
}
|
||||
|
@ -114,6 +115,7 @@ class FutureImpl<T> extends FutureBase<T> {
|
|||
return this;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Future<T> onComplete(Handler<AsyncResult<T>> handler) {
|
||||
Objects.requireNonNull(handler, "No null handler accepted");
|
||||
|
@ -152,6 +154,7 @@ class FutureImpl<T> extends FutureBase<T> {
|
|||
return this;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void addListener(Listener<T> listener) {
|
||||
Object v;
|
||||
|
@ -242,6 +245,7 @@ class FutureImpl<T> extends FutureBase<T> {
|
|||
sb.append(value);
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static class ListenerArray<T> extends ArrayList<Listener<T>> implements Listener<T> {
|
||||
@Override
|
||||
public void onSuccess(T value) {
|
||||
|
|
|
@ -16,7 +16,7 @@ public final class SucceededFuture<T> extends FutureBase<T> {
|
|||
/**
|
||||
* Stateless instance of empty results that can be shared safely.
|
||||
*/
|
||||
public static final SucceededFuture EMPTY = new SucceededFuture(null, null);
|
||||
public static final SucceededFuture<?> EMPTY = new SucceededFuture<>(null, null);
|
||||
|
||||
private final T result;
|
||||
|
||||
|
|
|
@ -85,7 +85,6 @@ public abstract class Dispatcher {
|
|||
Objects.requireNonNull(subscribers);
|
||||
Queue<Event> queueForThread = queue.get();
|
||||
queueForThread.offer(new Event(event, subscribers));
|
||||
|
||||
if (!dispatching.get()) {
|
||||
dispatching.set(true);
|
||||
try {
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
package org.xbib.event.bus;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Iterator;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
|
@ -134,6 +132,10 @@ public class EventBus {
|
|||
return identifier;
|
||||
}
|
||||
|
||||
public SubscriberRegistry getSubscribers() {
|
||||
return subscribers;
|
||||
}
|
||||
|
||||
/** Returns the default executor this event bus uses for dispatching events to subscribers. */
|
||||
final Executor executor() {
|
||||
return executor;
|
||||
|
@ -183,7 +185,7 @@ public class EventBus {
|
|||
* @param event event to post.
|
||||
*/
|
||||
public void post(Object event) {
|
||||
Iterator<Subscriber> eventSubscribers = subscribers.getSubscribers(event);
|
||||
Iterator<Subscriber> eventSubscribers = subscribers.getIterator(event);
|
||||
if (eventSubscribers.hasNext()) {
|
||||
dispatcher.dispatch(event, eventSubscribers);
|
||||
} else if (!(event instanceof DeadEvent)) {
|
||||
|
@ -197,33 +199,4 @@ public class EventBus {
|
|||
return "EventBus{" + identifier + "}";
|
||||
}
|
||||
|
||||
/** Simple logging handler for subscriber exceptions. */
|
||||
static final class LoggingHandler implements SubscriberExceptionHandler {
|
||||
static final LoggingHandler INSTANCE = new LoggingHandler();
|
||||
|
||||
@Override
|
||||
public void handleException(Throwable exception, SubscriberExceptionContext context) {
|
||||
Logger logger = logger(context);
|
||||
if (logger.isLoggable(Level.SEVERE)) {
|
||||
logger.log(Level.SEVERE, message(context), exception);
|
||||
}
|
||||
}
|
||||
|
||||
private static Logger logger(SubscriberExceptionContext context) {
|
||||
return Logger.getLogger(EventBus.class.getName() + "." + context.getEventBus().identifier());
|
||||
}
|
||||
|
||||
private static String message(SubscriberExceptionContext context) {
|
||||
Method method = context.getSubscriberMethod();
|
||||
return "Exception thrown by subscriber method "
|
||||
+ method.getName()
|
||||
+ '('
|
||||
+ method.getParameterTypes()[0].getName()
|
||||
+ ')'
|
||||
+ " on subscriber "
|
||||
+ context.getSubscriber()
|
||||
+ " when dispatching event: "
|
||||
+ context.getEvent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
37
src/main/java/org/xbib/event/bus/LoggingHandler.java
Normal file
37
src/main/java/org/xbib/event/bus/LoggingHandler.java
Normal file
|
@ -0,0 +1,37 @@
|
|||
package org.xbib.event.bus;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Simple logging handler for subscriber exceptions.
|
||||
*/
|
||||
final class LoggingHandler implements SubscriberExceptionHandler {
|
||||
static final LoggingHandler INSTANCE = new LoggingHandler();
|
||||
|
||||
@Override
|
||||
public void handleException(Throwable exception, SubscriberExceptionContext context) {
|
||||
Logger logger = logger(context);
|
||||
if (logger.isLoggable(Level.SEVERE)) {
|
||||
logger.log(Level.SEVERE, message(context), exception);
|
||||
}
|
||||
}
|
||||
|
||||
private static Logger logger(SubscriberExceptionContext context) {
|
||||
return Logger.getLogger(EventBus.class.getName() + "." + context.getEventBus().identifier());
|
||||
}
|
||||
|
||||
private static String message(SubscriberExceptionContext context) {
|
||||
Method method = context.getSubscriberMethod();
|
||||
return "Exception thrown by subscriber method "
|
||||
+ method.getName()
|
||||
+ '('
|
||||
+ method.getParameterTypes()[0].getName()
|
||||
+ ')'
|
||||
+ " on subscriber "
|
||||
+ context.getSubscriber()
|
||||
+ " when dispatching event: "
|
||||
+ context.getEvent();
|
||||
}
|
||||
}
|
|
@ -23,7 +23,7 @@ import org.xbib.event.bus.util.TypeToken;
|
|||
/**
|
||||
* Registry of subscribers to a single event bus.
|
||||
*/
|
||||
final class SubscriberRegistry {
|
||||
public final class SubscriberRegistry {
|
||||
|
||||
/**
|
||||
* All registered subscribers, indexed by event type.
|
||||
|
@ -43,7 +43,6 @@ final class SubscriberRegistry {
|
|||
|
||||
/** Registers all subscriber methods on the given listener object. */
|
||||
void register(Object listener) {
|
||||
|
||||
MultiMap<Class<?>, Subscriber> listenerMethods = findAllSubscribers(listener);
|
||||
for (Entry<Class<?>, Collection<Subscriber>> entry : listenerMethods.asMap().entrySet()) {
|
||||
Class<?> eventType = entry.getKey();
|
||||
|
@ -53,7 +52,6 @@ final class SubscriberRegistry {
|
|||
CopyOnWriteArraySet<Subscriber> newSet = new CopyOnWriteArraySet<>();
|
||||
eventSubscribers = firstNonNull(subscribers.putIfAbsent(eventType, newSet), newSet);
|
||||
}
|
||||
|
||||
eventSubscribers.addAll(eventMethodsInListener);
|
||||
}
|
||||
}
|
||||
|
@ -73,13 +71,12 @@ final class SubscriberRegistry {
|
|||
throw new IllegalArgumentException(
|
||||
"missing event subscriber for an annotated method. Is " + listener + " registered?");
|
||||
}
|
||||
|
||||
// don't try to remove the set if it's empty; that can't be done safely without a lock
|
||||
// anyway, if the set is empty it'll just be wrapping an array of length 0
|
||||
}
|
||||
}
|
||||
|
||||
Set<Subscriber> getSubscribersForTesting(Class<?> eventType) {
|
||||
public Set<Subscriber> getSubscribersForTesting(Class<?> eventType) {
|
||||
return firstNonNull(subscribers.get(eventType), new LinkedHashSet<>());
|
||||
}
|
||||
|
||||
|
@ -87,7 +84,7 @@ final class SubscriberRegistry {
|
|||
* Gets an iterator representing an immutable snapshot of all subscribers to the given event at
|
||||
* the time this method is called.
|
||||
*/
|
||||
Iterator<Subscriber> getSubscribers(Object event) {
|
||||
Iterator<Subscriber> getIterator(Object event) {
|
||||
Set<Class<?>> eventTypes = flattenHierarchy(event.getClass());
|
||||
List<Iterator<Subscriber>> subscriberIterators = new ArrayList<>(eventTypes.size());
|
||||
for (Class<?> eventType : eventTypes) {
|
||||
|
|
|
@ -20,7 +20,4 @@ public class SimpleClockEventConsumer implements EventConsumer {
|
|||
logger.info("received demo clock event, instant = " + event.getInstant());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
package org.xbib.event.generic;
|
||||
|
||||
import org.xbib.event.DefaultEvent;
|
||||
|
||||
public class DefaultGenericEvent extends DefaultEvent implements GenericEvent {
|
||||
|
||||
private Listener listener;
|
||||
|
||||
public DefaultGenericEvent() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
public DefaultGenericEvent(Listener listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
public DefaultGenericEvent setListener(Listener listener) {
|
||||
this.listener = listener;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Listener getListener() {
|
||||
return listener;
|
||||
}
|
||||
|
||||
public void received() {
|
||||
if (listener != null) {
|
||||
listener.listen(this);
|
||||
}
|
||||
}
|
||||
}
|
6
src/main/java/org/xbib/event/generic/GenericEvent.java
Normal file
6
src/main/java/org/xbib/event/generic/GenericEvent.java
Normal file
|
@ -0,0 +1,6 @@
|
|||
package org.xbib.event.generic;
|
||||
|
||||
import org.xbib.event.Event;
|
||||
|
||||
public interface GenericEvent extends Event {
|
||||
}
|
|
@ -1,9 +1,13 @@
|
|||
package org.xbib.event.generic;
|
||||
|
||||
import java.io.Closeable;
|
||||
import org.xbib.event.bus.AsyncEventBus;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class GenericEventManager implements Closeable {
|
||||
import org.xbib.event.bus.AsyncEventBus;
|
||||
import org.xbib.event.bus.Subscriber;
|
||||
import org.xbib.event.bus.SubscriberRegistry;
|
||||
|
||||
public class GenericEventManager {
|
||||
|
||||
private final AsyncEventBus eventBus;
|
||||
|
||||
|
@ -15,7 +19,36 @@ public class GenericEventManager implements Closeable {
|
|||
eventBus.post(event);
|
||||
}
|
||||
|
||||
public void post(DefaultGenericEvent event,
|
||||
CompletableFuture<Boolean> future) {
|
||||
SubscriberRegistry subscriberRegistry = eventBus.getSubscribers();
|
||||
Set<Subscriber> set = subscriberRegistry.getSubscribersForTesting(event.getClass());
|
||||
event.setListener(new WrappedListener(event.getListener(), set.size(), future));
|
||||
post(event);
|
||||
}
|
||||
|
||||
static class WrappedListener implements Listener {
|
||||
|
||||
private final Listener listener;
|
||||
|
||||
private int size;
|
||||
|
||||
private final CompletableFuture<Boolean> future;
|
||||
|
||||
public WrappedListener(Listener listener, int size, CompletableFuture<Boolean> future) {
|
||||
this.listener = listener;
|
||||
this.size = size;
|
||||
this.future = future;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
public void listen(GenericEvent event) {
|
||||
if (listener != null) {
|
||||
listener.listen(event);
|
||||
}
|
||||
if (--size == 0) {
|
||||
future.complete(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
7
src/main/java/org/xbib/event/generic/Listener.java
Normal file
7
src/main/java/org/xbib/event/generic/Listener.java
Normal file
|
@ -0,0 +1,7 @@
|
|||
package org.xbib.event.generic;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface Listener {
|
||||
|
||||
void listen(GenericEvent event);
|
||||
}
|
|
@ -10,6 +10,10 @@ import org.reactivestreams.Subscription;
|
|||
* @param <T>
|
||||
*/
|
||||
public class EmptySubscriber<T> implements org.reactivestreams.Subscriber<T> {
|
||||
|
||||
public EmptySubscriber() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSubscribe(Subscription subscription) {
|
||||
}
|
||||
|
|
|
@ -10,6 +10,9 @@ public class DefaultFileFollowEvent extends DefaultEvent implements FileFollowEv
|
|||
|
||||
private String content;
|
||||
|
||||
public DefaultFileFollowEvent() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPath(Path path) {
|
||||
this.path = path;
|
||||
|
|
|
@ -15,6 +15,10 @@ import java.util.concurrent.TimeoutException;
|
|||
* Abstract base class for {@link EventExecutorGroup} implementations.
|
||||
*/
|
||||
public abstract class AbstractEventExecutorGroup implements EventExecutorGroup {
|
||||
|
||||
protected AbstractEventExecutorGroup() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<?> submit(Runnable task) {
|
||||
return next().submit(task);
|
||||
|
|
|
@ -1097,7 +1097,7 @@ public abstract class SingleThreadEventExecutor extends AbstractScheduledEventEx
|
|||
|
||||
@Override
|
||||
public long id() {
|
||||
return t.getId();
|
||||
return t.threadId();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -7,7 +7,7 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
|
||||
public class CEFMessageParser extends MessageParser {
|
||||
public final class CEFMessageParser extends MessageParser {
|
||||
|
||||
private static final String CEF_PREFIX_PATTERN = "^(<(?<priority>\\d+)>)?(?<date>([a-zA-Z]{3}\\s+\\d+\\s+\\d+:\\d+:\\d+)|([0-9T:.Z-]+))\\s+(?<host>\\S+)\\s+CEF:(?<version>\\d+)\\|(?<data>.*)$";
|
||||
|
||||
|
|
|
@ -201,6 +201,9 @@ public class DefaultSyslogMessage implements SyslogMessage {
|
|||
|
||||
Map<String, Object> map;
|
||||
|
||||
private Builder() {
|
||||
}
|
||||
|
||||
public Builder date(LocalDateTime date) {
|
||||
this.date = date;
|
||||
return this;
|
||||
|
|
|
@ -3,7 +3,7 @@ package org.xbib.event.syslog;
|
|||
import java.time.LocalDateTime;
|
||||
import java.util.regex.Matcher;
|
||||
|
||||
public class RFC3164MessageParser extends MessageParser {
|
||||
public final class RFC3164MessageParser extends MessageParser {
|
||||
|
||||
private static final String PATTERN = "^(<(?<priority>\\d+)>)?(?<date>([a-zA-Z]{3}\\s+\\d+\\s+\\d+:\\d+:\\d+)|([0-9T:.Z-]+))\\s+(?<host>\\S+)\\s+((?<tag>[^\\[\\s\\]]+)(\\[(?<procid>\\d+)\\])?:)*\\s*(?<message>.+)$";
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ import java.time.LocalDateTime;
|
|||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
|
||||
public class RFC5424MessageParser extends MessageParser {
|
||||
public final class RFC5424MessageParser extends MessageParser {
|
||||
|
||||
private static final String PATTERN = "^<(?<priority>\\d+)>(?<version>\\d{1,3})\\s*(?<date>[0-9:+-TZ]+)\\s*(?<host>\\S+)\\s*(?<appname>\\S+)\\s*(?<procid>\\S+)\\s*(?<msgid>\\S+)\\s*(?<structureddata>(-|\\[.+\\]))\\s*(?<message>.+)$";
|
||||
|
||||
|
|
|
@ -64,7 +64,6 @@ public final class InternalThreadLocalMap {
|
|||
|
||||
private BitSet cleanerFlags;
|
||||
|
||||
/** @deprecated These padding fields will be removed in the future. */
|
||||
public long rp1, rp2, rp3, rp4, rp5, rp6, rp7, rp8;
|
||||
|
||||
static {
|
||||
|
|
80
src/test/java/org/xbib/event/EventManagerTest.java
Normal file
80
src/test/java/org/xbib/event/EventManagerTest.java
Normal file
|
@ -0,0 +1,80 @@
|
|||
package org.xbib.event;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.xbib.event.bus.Subscribe;
|
||||
import org.xbib.event.generic.DefaultGenericEvent;
|
||||
import org.xbib.event.generic.GenericEvent;
|
||||
import org.xbib.settings.Settings;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class EventManagerTest {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(EventManagerTest.class.getName());
|
||||
|
||||
@Test
|
||||
void testGenericEvents() {
|
||||
Settings settings = Settings.settingsBuilder()
|
||||
.build();
|
||||
TestEventConsumer consumer = new TestEventConsumer();
|
||||
EventManager eventManager = EventManager.builder(settings)
|
||||
.register(consumer)
|
||||
.build();
|
||||
eventManager.getGenericEventManager().post(new DefaultGenericEvent(e -> {
|
||||
logger.log(Level.INFO, "received event " + e);
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testGenericEventWithWaitForSubscriber() throws InterruptedException, ExecutionException {
|
||||
Settings settings = Settings.settingsBuilder()
|
||||
.build();
|
||||
TestEventConsumer consumer = new TestEventConsumer();
|
||||
EventManager eventManager = EventManager.builder(settings)
|
||||
.register(consumer)
|
||||
.build();
|
||||
CompletableFuture<GenericEvent> future = new CompletableFuture<>();
|
||||
eventManager.getGenericEventManager().post(new DefaultGenericEvent(e -> {
|
||||
logger.log(Level.INFO, "received event " + e);
|
||||
future.complete(e);
|
||||
}));
|
||||
GenericEvent e = future.get();
|
||||
logger.log(Level.INFO, "the event was received with result " + e + ", continuing");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGenericEventWithWaitForAllConsumers() throws ExecutionException, InterruptedException {
|
||||
Settings settings = Settings.settingsBuilder()
|
||||
.build();
|
||||
TestEventConsumer consumer1 = new TestEventConsumer();
|
||||
TestEventConsumer consumer2 = new TestEventConsumer();
|
||||
EventManager eventManager = EventManager.builder(settings)
|
||||
.register(consumer1)
|
||||
.register(consumer2)
|
||||
.loadEventConsumers()
|
||||
.build();
|
||||
CompletableFuture<Boolean> future = new CompletableFuture<>();
|
||||
eventManager.getGenericEventManager().post(new DefaultGenericEvent(e -> {
|
||||
logger.log(Level.INFO, "received event " + e);
|
||||
}), future);
|
||||
Boolean b = future.get();
|
||||
if (b != null && b) {
|
||||
logger.log(Level.INFO, "the event was received by all consumers, continuing");
|
||||
}
|
||||
}
|
||||
|
||||
private static class TestEventConsumer implements EventConsumer {
|
||||
|
||||
TestEventConsumer() {
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onEvent(DefaultGenericEvent event) {
|
||||
event.received();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,8 +18,4 @@ public class TestClockEventConsumer implements EventConsumer {
|
|||
void onEvent(TestClockEvent event) {
|
||||
logger.log(Level.INFO, "received test clock event on " + Instant.now() + " event instant = " + event.getInstant());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,8 +19,4 @@ public class TestFileFollowEventConsumer implements EventConsumer {
|
|||
void onEvent(TestFileFollowEvent event) {
|
||||
logger.log(Level.INFO, "received filefollow event path = " + event.getPath() + " content = " + event.getContent());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,4 @@ public class TestTimerEventConsumer implements EventConsumer {
|
|||
logger.log(Level.INFO, "received test timer event on " + Instant.now() + " event instant = " + event.getInstant());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue