cleanups to EventListenerGroup(Impl)
Signed-off-by: Gavin King <gavin@hibernate.org>
This commit is contained in:
parent
48fc2ee66d
commit
052eb0b78c
|
@ -7,7 +7,6 @@
|
||||||
package org.hibernate.event.service.internal;
|
package org.hibernate.event.service.internal;
|
||||||
|
|
||||||
import java.lang.reflect.Array;
|
import java.lang.reflect.Array;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
@ -32,6 +31,8 @@ import org.jboss.logging.Logger;
|
||||||
|
|
||||||
import static java.util.Arrays.asList;
|
import static java.util.Arrays.asList;
|
||||||
import static java.util.Collections.emptyList;
|
import static java.util.Collections.emptyList;
|
||||||
|
import static java.util.Collections.singleton;
|
||||||
|
import static java.util.concurrent.CompletableFuture.completedFuture;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Standard EventListenerGroup implementation
|
* Standard EventListenerGroup implementation
|
||||||
|
@ -42,8 +43,26 @@ import static java.util.Collections.emptyList;
|
||||||
class EventListenerGroupImpl<T> implements EventListenerGroup<T> {
|
class EventListenerGroupImpl<T> implements EventListenerGroup<T> {
|
||||||
|
|
||||||
private static final Logger log = Logger.getLogger( EventListenerGroupImpl.class );
|
private static final Logger log = Logger.getLogger( EventListenerGroupImpl.class );
|
||||||
private static final Set<DuplicationStrategy> DEFAULT_DUPLICATION_STRATEGIES = Collections.unmodifiableSet( makeDefaultDuplicationStrategy() );
|
|
||||||
private static final CompletableFuture COMPLETED = CompletableFuture.completedFuture( null );
|
private static final DuplicationStrategy DEFAULT_DUPLICATION_STRATEGY =
|
||||||
|
new DuplicationStrategy() {
|
||||||
|
@Override
|
||||||
|
public boolean areMatch(Object listener, Object original) {
|
||||||
|
return listener.getClass().equals( original.getClass() );
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public Action getAction() {
|
||||||
|
return Action.ERROR;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
private static final Set<DuplicationStrategy> DEFAULT_DUPLICATION_STRATEGIES =
|
||||||
|
singleton( DEFAULT_DUPLICATION_STRATEGY );
|
||||||
|
|
||||||
|
private static final CompletableFuture<?> COMPLETED = completedFuture( null );
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private static <R> CompletableFuture<R> nullCompletion() {
|
||||||
|
return (CompletableFuture<R>) COMPLETED;
|
||||||
|
}
|
||||||
|
|
||||||
private final EventType<T> eventType;
|
private final EventType<T> eventType;
|
||||||
private final CallbackRegistry callbackRegistry;
|
private final CallbackRegistry callbackRegistry;
|
||||||
|
@ -56,10 +75,7 @@ class EventListenerGroupImpl<T> implements EventListenerGroup<T> {
|
||||||
private volatile T[] listeners = null;
|
private volatile T[] listeners = null;
|
||||||
private volatile List<T> listenersAsList = emptyList();
|
private volatile List<T> listenersAsList = emptyList();
|
||||||
|
|
||||||
public EventListenerGroupImpl(
|
public EventListenerGroupImpl(EventType<T> eventType, CallbackRegistry callbackRegistry, boolean isJpaBootstrap) {
|
||||||
EventType<T> eventType,
|
|
||||||
CallbackRegistry callbackRegistry,
|
|
||||||
boolean isJpaBootstrap) {
|
|
||||||
this.eventType = eventType;
|
this.eventType = eventType;
|
||||||
this.callbackRegistry = callbackRegistry;
|
this.callbackRegistry = callbackRegistry;
|
||||||
this.isJpaBootstrap = isJpaBootstrap;
|
this.isJpaBootstrap = isJpaBootstrap;
|
||||||
|
@ -83,7 +99,8 @@ class EventListenerGroupImpl<T> implements EventListenerGroup<T> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void clear() {
|
public void clear() {
|
||||||
//Odd semantics: we're expected (for backwards compatibility) to also clear the default DuplicationStrategy.
|
//Odd semantics: we're expected (for backwards compatibility)
|
||||||
|
// to also clear the default DuplicationStrategy.
|
||||||
duplicationStrategies = new LinkedHashSet<>();
|
duplicationStrategies = new LinkedHashSet<>();
|
||||||
setListeners( null );
|
setListeners( null );
|
||||||
}
|
}
|
||||||
|
@ -92,13 +109,10 @@ class EventListenerGroupImpl<T> implements EventListenerGroup<T> {
|
||||||
// ensure consistency between the two fields by delegating any mutation to both
|
// ensure consistency between the two fields by delegating any mutation to both
|
||||||
// fields to this method.
|
// fields to this method.
|
||||||
private synchronized void setListeners(T[] newListeners) {
|
private synchronized void setListeners(T[] newListeners) {
|
||||||
this.listeners = newListeners;
|
listeners = newListeners;
|
||||||
if ( newListeners == null || newListeners.length == 0 ) {
|
listenersAsList = newListeners == null || newListeners.length == 0
|
||||||
this.listenersAsList = emptyList();
|
? emptyList()
|
||||||
}
|
: asList( newListeners );
|
||||||
else {
|
|
||||||
this.listenersAsList = asList( newListeners );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -107,7 +121,7 @@ class EventListenerGroupImpl<T> implements EventListenerGroup<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final <U> void fireLazyEventOnEachListener(final Supplier<U> eventSupplier, final BiConsumer<T,U> actionOnEvent) {
|
public final <U> void fireLazyEventOnEachListener(Supplier<U> eventSupplier, BiConsumer<T,U> actionOnEvent) {
|
||||||
final T[] ls = listeners;
|
final T[] ls = listeners;
|
||||||
if ( ls != null && ls.length != 0 ) {
|
if ( ls != null && ls.length != 0 ) {
|
||||||
final U event = eventSupplier.get();
|
final U event = eventSupplier.get();
|
||||||
|
@ -119,7 +133,7 @@ class EventListenerGroupImpl<T> implements EventListenerGroup<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final <U> void fireEventOnEachListener(final U event, final BiConsumer<T,U> actionOnEvent) {
|
public final <U> void fireEventOnEachListener(U event, BiConsumer<T,U> actionOnEvent) {
|
||||||
final T[] ls = listeners;
|
final T[] ls = listeners;
|
||||||
if ( ls != null ) {
|
if ( ls != null ) {
|
||||||
//noinspection ForLoopReplaceableByForEach
|
//noinspection ForLoopReplaceableByForEach
|
||||||
|
@ -130,7 +144,7 @@ class EventListenerGroupImpl<T> implements EventListenerGroup<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <U,X> void fireEventOnEachListener(final U event, final X parameter, final EventActionWithParameter<T, U, X> actionOnEvent) {
|
public <U,X> void fireEventOnEachListener(U event, X parameter, EventActionWithParameter<T, U, X> actionOnEvent) {
|
||||||
final T[] ls = listeners;
|
final T[] ls = listeners;
|
||||||
if ( ls != null ) {
|
if ( ls != null ) {
|
||||||
//noinspection ForLoopReplaceableByForEach
|
//noinspection ForLoopReplaceableByForEach
|
||||||
|
@ -144,9 +158,9 @@ class EventListenerGroupImpl<T> implements EventListenerGroup<T> {
|
||||||
public <R, U, RL> CompletionStage<R> fireEventOnEachListener(
|
public <R, U, RL> CompletionStage<R> fireEventOnEachListener(
|
||||||
final U event,
|
final U event,
|
||||||
final Function<RL, Function<U, CompletionStage<R>>> fun) {
|
final Function<RL, Function<U, CompletionStage<R>>> fun) {
|
||||||
CompletionStage<R> ret = COMPLETED;
|
CompletionStage<R> ret = nullCompletion();
|
||||||
final T[] ls = listeners;
|
final T[] ls = listeners;
|
||||||
if ( ls != null && ls.length != 0 ) {
|
if ( ls != null ) {
|
||||||
for ( T listener : ls ) {
|
for ( T listener : ls ) {
|
||||||
//to preserve atomicity of the Session methods
|
//to preserve atomicity of the Session methods
|
||||||
//call apply() from within the arg of thenCompose()
|
//call apply() from within the arg of thenCompose()
|
||||||
|
@ -159,9 +173,9 @@ class EventListenerGroupImpl<T> implements EventListenerGroup<T> {
|
||||||
@Override
|
@Override
|
||||||
public <R, U, RL, X> CompletionStage<R> fireEventOnEachListener(
|
public <R, U, RL, X> CompletionStage<R> fireEventOnEachListener(
|
||||||
U event, X param, Function<RL, BiFunction<U, X, CompletionStage<R>>> fun) {
|
U event, X param, Function<RL, BiFunction<U, X, CompletionStage<R>>> fun) {
|
||||||
CompletionStage<R> ret = COMPLETED;
|
CompletionStage<R> ret = nullCompletion();
|
||||||
final T[] ls = listeners;
|
final T[] ls = listeners;
|
||||||
if ( ls != null && ls.length != 0 ) {
|
if ( ls != null ) {
|
||||||
for ( T listener : ls ) {
|
for ( T listener : ls ) {
|
||||||
//to preserve atomicity of the Session methods
|
//to preserve atomicity of the Session methods
|
||||||
//call apply() from within the arg of thenCompose()
|
//call apply() from within the arg of thenCompose()
|
||||||
|
@ -173,9 +187,9 @@ class EventListenerGroupImpl<T> implements EventListenerGroup<T> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <R, U, RL> CompletionStage<R> fireLazyEventOnEachListener(
|
public <R, U, RL> CompletionStage<R> fireLazyEventOnEachListener(
|
||||||
final Supplier<U> eventSupplier,
|
Supplier<U> eventSupplier,
|
||||||
final Function<RL, Function<U, CompletionStage<R>>> fun) {
|
Function<RL, Function<U, CompletionStage<R>>> fun) {
|
||||||
CompletionStage<R> ret = COMPLETED;
|
CompletionStage<R> ret = nullCompletion();
|
||||||
final T[] ls = listeners;
|
final T[] ls = listeners;
|
||||||
if ( ls != null && ls.length != 0 ) {
|
if ( ls != null && ls.length != 0 ) {
|
||||||
final U event = eventSupplier.get();
|
final U event = eventSupplier.get();
|
||||||
|
@ -191,7 +205,8 @@ class EventListenerGroupImpl<T> implements EventListenerGroup<T> {
|
||||||
@Override
|
@Override
|
||||||
public void addDuplicationStrategy(DuplicationStrategy strategy) {
|
public void addDuplicationStrategy(DuplicationStrategy strategy) {
|
||||||
if ( duplicationStrategies == DEFAULT_DUPLICATION_STRATEGIES ) {
|
if ( duplicationStrategies == DEFAULT_DUPLICATION_STRATEGIES ) {
|
||||||
duplicationStrategies = makeDefaultDuplicationStrategy();
|
// At minimum make sure we do not register the same exact listener class multiple times.
|
||||||
|
duplicationStrategies = new LinkedHashSet<>( DEFAULT_DUPLICATION_STRATEGIES );
|
||||||
}
|
}
|
||||||
duplicationStrategies.add( strategy );
|
duplicationStrategies.add( strategy );
|
||||||
}
|
}
|
||||||
|
@ -212,19 +227,17 @@ class EventListenerGroupImpl<T> implements EventListenerGroup<T> {
|
||||||
|
|
||||||
private void internalAppend(T listener) {
|
private void internalAppend(T listener) {
|
||||||
prepareListener( listener );
|
prepareListener( listener );
|
||||||
final T[] listenersRead = this.listeners;
|
final T[] listenersRead = listeners;
|
||||||
final T[] listenersWrite;
|
final T[] listenersWrite;
|
||||||
|
|
||||||
if ( listenersRead == null ) {
|
if ( listenersRead == null ) {
|
||||||
//noinspection unchecked
|
listenersWrite = createListenerArrayForWrite( 1 );
|
||||||
listenersWrite = (T[]) Array.newInstance( eventType.baseListenerInterface(), 1 );
|
|
||||||
listenersWrite[0] = listener;
|
listenersWrite[0] = listener;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
final int size = listenersRead.length;
|
final int size = listenersRead.length;
|
||||||
|
|
||||||
//noinspection unchecked
|
listenersWrite = createListenerArrayForWrite( size + 1 );
|
||||||
listenersWrite = (T[]) Array.newInstance( eventType.baseListenerInterface(), size+1 );
|
|
||||||
|
|
||||||
// first copy the existing listeners
|
// first copy the existing listeners
|
||||||
System.arraycopy( listenersRead, 0, listenersWrite, 0, size );
|
System.arraycopy( listenersRead, 0, listenersWrite, 0, size );
|
||||||
|
@ -251,19 +264,17 @@ class EventListenerGroupImpl<T> implements EventListenerGroup<T> {
|
||||||
|
|
||||||
private void internalPrepend(T listener) {
|
private void internalPrepend(T listener) {
|
||||||
prepareListener( listener );
|
prepareListener( listener );
|
||||||
final T[] listenersRead = this.listeners;
|
final T[] listenersRead = listeners;
|
||||||
final T[] listenersWrite;
|
final T[] listenersWrite;
|
||||||
|
|
||||||
if ( listenersRead == null ) {
|
if ( listenersRead == null ) {
|
||||||
//noinspection unchecked
|
listenersWrite = createListenerArrayForWrite( 1 );
|
||||||
listenersWrite = (T[]) Array.newInstance( eventType.baseListenerInterface(), 1 );
|
|
||||||
listenersWrite[0] = listener;
|
listenersWrite[0] = listener;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
final int size = listenersRead.length;
|
final int size = listenersRead.length;
|
||||||
|
|
||||||
//noinspection unchecked
|
listenersWrite = createListenerArrayForWrite( size + 1 );
|
||||||
listenersWrite = (T[]) Array.newInstance( eventType.baseListenerInterface(), size+1 );
|
|
||||||
|
|
||||||
// put the new one first
|
// put the new one first
|
||||||
listenersWrite[0] = listener;
|
listenersWrite[0] = listener;
|
||||||
|
@ -275,13 +286,15 @@ class EventListenerGroupImpl<T> implements EventListenerGroup<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleListenerAddition(T listener, Consumer<T> additionHandler) {
|
private void handleListenerAddition(T listener, Consumer<T> additionHandler) {
|
||||||
final T[] listenersRead = this.listeners;
|
final T[] listenersRead = listeners;
|
||||||
if ( listenersRead == null ) {
|
if ( listenersRead == null ) {
|
||||||
additionHandler.accept( listener );
|
additionHandler.accept( listener );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final T[] listenersWrite = (T[]) Array.newInstance( eventType.baseListenerInterface(), listenersRead.length );
|
int size = listenersRead.length;
|
||||||
System.arraycopy( listenersRead, 0, listenersWrite, 0, listenersRead.length );
|
|
||||||
|
final T[] listenersWrite = createListenerArrayForWrite( size );
|
||||||
|
System.arraycopy( listenersRead, 0, listenersWrite, 0, size );
|
||||||
|
|
||||||
final boolean debugEnabled = log.isDebugEnabled();
|
final boolean debugEnabled = log.isDebugEnabled();
|
||||||
|
|
||||||
|
@ -292,40 +305,37 @@ class EventListenerGroupImpl<T> implements EventListenerGroup<T> {
|
||||||
// strategy's action. Control it returned immediately after applying the action
|
// strategy's action. Control it returned immediately after applying the action
|
||||||
// on match - meaning no further strategies are checked...
|
// on match - meaning no further strategies are checked...
|
||||||
|
|
||||||
for ( int i = 0; i < listenersRead.length; i++ ) {
|
for ( int i = 0; i < size; i++ ) {
|
||||||
final T existingListener = listenersRead[i];
|
final T existingListener = listenersRead[i];
|
||||||
if ( debugEnabled ) {
|
if ( debugEnabled ) {
|
||||||
log.debugf(
|
log.debugf( "Checking incoming listener [`%s`] for match against existing listener [`%s`]",
|
||||||
"Checking incoming listener [`%s`] for match against existing listener [`%s`]",
|
listener, existingListener );
|
||||||
listener,
|
|
||||||
existingListener
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( strategy.areMatch( listener, existingListener ) ) {
|
if ( strategy.areMatch( listener, existingListener ) ) {
|
||||||
if ( debugEnabled ) {
|
if ( debugEnabled ) {
|
||||||
log.debugf( "Found listener match between `%s` and `%s`", listener, existingListener );
|
log.debugf( "Found listener match between `%s` and `%s`",
|
||||||
|
listener, existingListener );
|
||||||
}
|
}
|
||||||
|
|
||||||
switch ( strategy.getAction() ) {
|
final DuplicationStrategy.Action action = strategy.getAction();
|
||||||
case ERROR: {
|
switch (action) {
|
||||||
|
case ERROR:
|
||||||
throw new EventListenerRegistrationException( "Duplicate event listener found" );
|
throw new EventListenerRegistrationException( "Duplicate event listener found" );
|
||||||
}
|
case KEEP_ORIGINAL:
|
||||||
case KEEP_ORIGINAL: {
|
|
||||||
if ( debugEnabled ) {
|
if ( debugEnabled ) {
|
||||||
log.debugf( "Skipping listener registration (%s) : `%s`", strategy.getAction(), listener );
|
log.debugf( "Skipping listener registration (%s) : `%s`",
|
||||||
|
action, listener );
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
case REPLACE_ORIGINAL:
|
||||||
case REPLACE_ORIGINAL: {
|
|
||||||
if ( debugEnabled ) {
|
if ( debugEnabled ) {
|
||||||
log.debugf( "Replacing listener registration (%s) : `%s` -> `%s`", strategy.getAction(), existingListener, listener );
|
log.debugf( "Replacing listener registration (%s) : `%s` -> `%s`",
|
||||||
|
action, existingListener, listener );
|
||||||
}
|
}
|
||||||
prepareListener( listener );
|
prepareListener( listener );
|
||||||
|
|
||||||
listenersWrite[i] = listener;
|
listenersWrite[i] = listener;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// we've found a match - we should return: the match action has already been applied at this point
|
// we've found a match - we should return: the match action has already been applied at this point
|
||||||
// apply all pending changes:
|
// apply all pending changes:
|
||||||
|
@ -335,32 +345,35 @@ class EventListenerGroupImpl<T> implements EventListenerGroup<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// we did not find any match.. add it
|
// we did not find any match, add it
|
||||||
checkAgainstBaseInterface( listener );
|
checkAgainstBaseInterface( listener );
|
||||||
performInjections( listener );
|
performInjections( listener );
|
||||||
additionHandler.accept( listener );
|
additionHandler.accept( listener );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private T[] createListenerArrayForWrite(int len) {
|
||||||
|
return (T[]) Array.newInstance( eventType.baseListenerInterface(), len );
|
||||||
|
}
|
||||||
|
|
||||||
private void prepareListener(T listener) {
|
private void prepareListener(T listener) {
|
||||||
checkAgainstBaseInterface( listener );
|
checkAgainstBaseInterface( listener );
|
||||||
performInjections( listener );
|
performInjections( listener );
|
||||||
}
|
}
|
||||||
|
|
||||||
private void performInjections(T listener) {
|
private void performInjections(T listener) {
|
||||||
if ( listener instanceof CallbackRegistryConsumer ) {
|
if ( listener instanceof CallbackRegistryConsumer consumer ) {
|
||||||
( (CallbackRegistryConsumer) listener ).injectCallbackRegistry( callbackRegistry );
|
consumer.injectCallbackRegistry( callbackRegistry );
|
||||||
}
|
}
|
||||||
|
if ( listener instanceof JpaBootstrapSensitive sensitive ) {
|
||||||
if ( listener instanceof JpaBootstrapSensitive ) {
|
sensitive.wasJpaBootstrap( isJpaBootstrap );
|
||||||
( (JpaBootstrapSensitive) listener ).wasJpaBootstrap( isJpaBootstrap );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkAgainstBaseInterface(T listener) {
|
private void checkAgainstBaseInterface(T listener) {
|
||||||
if ( !eventType.baseListenerInterface().isInstance( listener ) ) {
|
if ( !eventType.baseListenerInterface().isInstance( listener ) ) {
|
||||||
throw new EventListenerRegistrationException(
|
throw new EventListenerRegistrationException( "Listener did not implement expected interface ["
|
||||||
"Listener did not implement expected interface [" + eventType.baseListenerInterface().getName() + "]"
|
+ eventType.baseListenerInterface().getName() + "]" );
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -372,26 +385,6 @@ class EventListenerGroupImpl<T> implements EventListenerGroup<T> {
|
||||||
@Override
|
@Override
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public final Iterable<T> listeners() {
|
public final Iterable<T> listeners() {
|
||||||
return this.listenersAsList;
|
return listenersAsList;
|
||||||
}
|
|
||||||
|
|
||||||
private static Set<DuplicationStrategy> makeDefaultDuplicationStrategy() {
|
|
||||||
final Set<DuplicationStrategy> duplicationStrategies = new LinkedHashSet<>();
|
|
||||||
duplicationStrategies.add(
|
|
||||||
// At minimum make sure we do not register the same exact listener class multiple times.
|
|
||||||
new DuplicationStrategy() {
|
|
||||||
@Override
|
|
||||||
public boolean areMatch(Object listener, Object original) {
|
|
||||||
return listener.getClass().equals( original.getClass() );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Action getAction() {
|
|
||||||
return Action.ERROR;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
|
||||||
return duplicationStrategies;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -49,9 +49,9 @@ public interface EventListenerGroup<T> {
|
||||||
/**
|
/**
|
||||||
* Mechanism to more finely control the notion of duplicates.
|
* Mechanism to more finely control the notion of duplicates.
|
||||||
* <p>
|
* <p>
|
||||||
* For example, say you are registering listeners for an extension library. This extension library
|
* For example, say you are registering listeners for an extension library. This
|
||||||
* could define a "marker interface" which indicates listeners related to it and register a strategy
|
* extension library could define a "marker interface" which indicates listeners
|
||||||
* that checks against that marker interface.
|
* related to it and register a strategy that checks against that marker interface.
|
||||||
*
|
*
|
||||||
* @param strategy The duplication strategy
|
* @param strategy The duplication strategy
|
||||||
*/
|
*/
|
||||||
|
@ -64,10 +64,11 @@ public interface EventListenerGroup<T> {
|
||||||
void prependListeners(T... listeners);
|
void prependListeners(T... listeners);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears both the list of event listeners and all DuplicationStrategy,
|
* Clears both the list of event listeners and every {@link DuplicationStrategy},
|
||||||
* including the default duplication strategy.
|
* including the default duplication strategy.
|
||||||
* @deprecated likely want to use {@link #clearListeners()} instead, which doesn't
|
*
|
||||||
* also reset the registered DuplicationStrategy(ies).
|
* @deprecated Use {@link #clearListeners()} instead, which doesn't also reset
|
||||||
|
* the registered {@link DuplicationStrategy}s.
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
void clear();
|
void clear();
|
||||||
|
@ -80,57 +81,65 @@ public interface EventListenerGroup<T> {
|
||||||
/**
|
/**
|
||||||
* Fires an event on each registered event listener of this group.
|
* Fires an event on each registered event listener of this group.
|
||||||
*
|
*
|
||||||
* Implementation note (performance):
|
* @implNote The first argument is a supplier so that events can avoid being created
|
||||||
* the first argument is a supplier so that events can avoid being created when no listener is registered.
|
* when no listener is registered; The second argument is specifically
|
||||||
* the second argument is specifically designed to avoid needing a capturing lambda.
|
* designed to avoid needing a capturing lambda.
|
||||||
*
|
*
|
||||||
* @param <U> the kind of event
|
* @param <U> the kind of event
|
||||||
*/
|
*/
|
||||||
@Incubating
|
@Incubating
|
||||||
<U> void fireLazyEventOnEachListener(final Supplier<U> eventSupplier, final BiConsumer<T,U> actionOnEvent);
|
<U> void fireLazyEventOnEachListener(Supplier<U> eventSupplier, BiConsumer<T,U> actionOnEvent);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Similar as {@link #fireLazyEventOnEachListener(Supplier, BiConsumer)} except it doesn't use a {{@link Supplier}}:
|
* Similar as {@link #fireLazyEventOnEachListener(Supplier, BiConsumer)} except it
|
||||||
* useful when there is no need to lazily initialize the event.
|
* doesn't use a {{@link Supplier}}. Useful when there is no need to lazily initialize
|
||||||
|
* the event.
|
||||||
*
|
*
|
||||||
* @param <U> the kind of event
|
* @param <U> the kind of event
|
||||||
*/
|
*/
|
||||||
@Incubating
|
@Incubating
|
||||||
<U> void fireEventOnEachListener(final U event, final BiConsumer<T,U> actionOnEvent);
|
<U> void fireEventOnEachListener(U event, BiConsumer<T,U> actionOnEvent);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Similar to {@link #fireEventOnEachListener(Object, BiConsumer)}, but allows passing a third parameter
|
* Similar to {@link #fireEventOnEachListener(Object, BiConsumer)}, but allows passing
|
||||||
* to the consumer; our code based occasionally needs a third parameter: having this additional variant
|
* a third parameter to the consumer; our code based occasionally needs a third parameter:
|
||||||
* allows using the optimal iteration more extensively and reduce allocations.
|
* having this additional variant allows using the optimal iteration more extensively and
|
||||||
|
* reduce allocations.
|
||||||
*/
|
*/
|
||||||
@Incubating
|
@Incubating
|
||||||
<U,X> void fireEventOnEachListener(final U event, X param, final EventActionWithParameter<T,U,X> actionOnEvent);
|
<U,X> void fireEventOnEachListener(U event, X param, EventActionWithParameter<T,U,X> actionOnEvent);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Similar to {@link #fireEventOnEachListener(Object, Function)}, but Reactive friendly: it chains
|
* Similar to {@link #fireEventOnEachListener(Object, BiConsumer)}, but Reactive friendly:
|
||||||
* processing of the same event on each Reactive Listener, and returns a {@link CompletionStage} of type R.
|
* it chains processing of the same event on each Reactive Listener, and returns a
|
||||||
* The various generic types allow using this for each concrete event type and flexible return types.
|
* {@link CompletionStage} of type R. The various generic types allow using this for each
|
||||||
* <p>Used by Hibernate Reactive</p>
|
* concrete event type and flexible return types.
|
||||||
|
* <p>
|
||||||
|
* <em>Used by Hibernate Reactive</em>
|
||||||
|
*
|
||||||
* @param event The event being fired
|
* @param event The event being fired
|
||||||
* @param fun The function combining each event listener with the event
|
* @param fun The function combining each event listener with the event
|
||||||
* @param <R> the return type of the returned CompletionStage
|
* @param <R> the return type of the returned CompletionStage
|
||||||
* @param <U> the type of the event being fired on each listener
|
* @param <U> the type of the event being fired on each listener
|
||||||
* @param <RL> the type of ReactiveListener: each listener of type T will be casted to it.
|
* @param <RL> the type of ReactiveListener: each listener of type T will be cast to this type
|
||||||
* @return the composite completion stage of invoking fun(event) on each listener.
|
* @return the composite completion stage of invoking fun(event) on each listener.
|
||||||
*/
|
*/
|
||||||
@Incubating
|
@Incubating
|
||||||
<R, U, RL> CompletionStage<R> fireEventOnEachListener(final U event, final Function<RL, Function<U, CompletionStage<R>>> fun);
|
<R, U, RL> CompletionStage<R> fireEventOnEachListener(U event, Function<RL, Function<U, CompletionStage<R>>> fun);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Similar to {@link #fireEventOnEachListener(Object, Object, Function)}, but Reactive friendly: it chains
|
* Similar to {@link #fireEventOnEachListener(Object, Object, EventActionWithParameter)},
|
||||||
* processing of the same event on each Reactive Listener, and returns a {@link CompletionStage} of type R.
|
* but Reactive friendly: it chains processing of the same event on each Reactive Listener,
|
||||||
* The various generic types allow using this for each concrete event type and flexible return types.
|
* and returns a {@link CompletionStage} of type R. The various generic types allow using
|
||||||
* <p>Used by Hibernate Reactive</p>
|
* this for each concrete event type and flexible return types.
|
||||||
|
* <p>
|
||||||
|
* <em>Used by Hibernate Reactive</em>
|
||||||
|
*
|
||||||
* @param event The event being fired
|
* @param event The event being fired
|
||||||
* @param fun The function combining each event listener with the event
|
* @param fun The function combining each event listener with the event
|
||||||
* @param <R> the return type of the returned CompletionStage
|
* @param <R> the return type of the returned CompletionStage
|
||||||
* @param <U> the type of the event being fired on each listener
|
* @param <U> the type of the event being fired on each listener
|
||||||
* @param <RL> the type of ReactiveListener: each listener of type T will be casted to it.
|
* @param <RL> the type of ReactiveListener: each listener of type T will be cast to this type
|
||||||
* @param <X> an additional parameter to be passed to the function fun
|
* @param <X> an additional parameter to be passed to the function fun
|
||||||
* @return the composite completion stage of invoking fun(event) on each listener.
|
* @return the composite completion stage of invoking fun(event) on each listener.
|
||||||
*/
|
*/
|
||||||
|
@ -138,21 +147,26 @@ public interface EventListenerGroup<T> {
|
||||||
<R, U, RL, X> CompletionStage<R> fireEventOnEachListener(U event, X param, Function<RL, BiFunction<U, X, CompletionStage<R>>> fun);
|
<R, U, RL, X> CompletionStage<R> fireEventOnEachListener(U event, X param, Function<RL, BiFunction<U, X, CompletionStage<R>>> fun);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Similar to {@link #fireLazyEventOnEachListener(Supplier, BiConsumer)}, but Reactive friendly: it chains
|
* Similar to {@link #fireLazyEventOnEachListener(Supplier, BiConsumer)}, but Reactive
|
||||||
* processing of the same event on each Reactive Listener, and returns a {@link CompletionStage} of type R.
|
* friendly: it chains processing of the same event on each Reactive Listener, and returns
|
||||||
* The various generic types allow using this for each concrete event type and flexible return types.
|
* a {@link CompletionStage} of type R. The various generic types allow using this for
|
||||||
* <p>This variant expects a Supplier of the event, rather than the event directly; this is useful for the
|
* each concrete event type and flexible return types.
|
||||||
* event types which are commonly configured with no listeners at all, so to allow skipping creating the
|
* <p>
|
||||||
* event; use only for event types which are known to be expensive while the listeners are commonly empty.</p>
|
* This variant expects a Supplier of the event, rather than the event directly; this is
|
||||||
* <p>Used by Hibernate Reactive</p>
|
* useful for the event types which are commonly configured with no listeners at all, so
|
||||||
|
* to allow skipping creating the event; use only for event types which are known to be
|
||||||
|
* expensive while the listeners are commonly empty.
|
||||||
|
* <p>
|
||||||
|
* <em>Used by Hibernate Reactive</em>
|
||||||
|
*
|
||||||
* @param eventSupplier A supplier able to produce the actual event
|
* @param eventSupplier A supplier able to produce the actual event
|
||||||
* @param fun The function combining each event listener with the event
|
* @param fun The function combining each event listener with the event
|
||||||
* @param <R> the return type of the returned CompletionStage
|
* @param <R> the return type of the returned CompletionStage
|
||||||
* @param <U> the type of the event being fired on each listener
|
* @param <U> the type of the event being fired on each listener
|
||||||
* @param <RL> the type of ReactiveListener: each listener of type T will be casted to it.
|
* @param <RL> the type of ReactiveListener: each listener of type T will be to this type
|
||||||
* @return the composite completion stage of invoking fun(event) on each listener.
|
* @return the composite completion stage of invoking fun(event) on each listener.
|
||||||
*/
|
*/
|
||||||
@Incubating
|
@Incubating
|
||||||
<R, U, RL> CompletionStage<R> fireLazyEventOnEachListener(final Supplier<U> eventSupplier, final Function<RL, Function<U, CompletionStage<R>>> fun);
|
<R, U, RL> CompletionStage<R> fireLazyEventOnEachListener(Supplier<U> eventSupplier, Function<RL, Function<U, CompletionStage<R>>> fun);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue