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;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
@ -32,6 +31,8 @@ import org.jboss.logging.Logger;
|
|||
|
||||
import static java.util.Arrays.asList;
|
||||
import static java.util.Collections.emptyList;
|
||||
import static java.util.Collections.singleton;
|
||||
import static java.util.concurrent.CompletableFuture.completedFuture;
|
||||
|
||||
/**
|
||||
* Standard EventListenerGroup implementation
|
||||
|
@ -42,8 +43,26 @@ import static java.util.Collections.emptyList;
|
|||
class EventListenerGroupImpl<T> implements EventListenerGroup<T> {
|
||||
|
||||
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 CallbackRegistry callbackRegistry;
|
||||
|
@ -56,10 +75,7 @@ class EventListenerGroupImpl<T> implements EventListenerGroup<T> {
|
|||
private volatile T[] listeners = null;
|
||||
private volatile List<T> listenersAsList = emptyList();
|
||||
|
||||
public EventListenerGroupImpl(
|
||||
EventType<T> eventType,
|
||||
CallbackRegistry callbackRegistry,
|
||||
boolean isJpaBootstrap) {
|
||||
public EventListenerGroupImpl(EventType<T> eventType, CallbackRegistry callbackRegistry, boolean isJpaBootstrap) {
|
||||
this.eventType = eventType;
|
||||
this.callbackRegistry = callbackRegistry;
|
||||
this.isJpaBootstrap = isJpaBootstrap;
|
||||
|
@ -83,7 +99,8 @@ class EventListenerGroupImpl<T> implements EventListenerGroup<T> {
|
|||
|
||||
@Override
|
||||
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<>();
|
||||
setListeners( null );
|
||||
}
|
||||
|
@ -92,13 +109,10 @@ class EventListenerGroupImpl<T> implements EventListenerGroup<T> {
|
|||
// ensure consistency between the two fields by delegating any mutation to both
|
||||
// fields to this method.
|
||||
private synchronized void setListeners(T[] newListeners) {
|
||||
this.listeners = newListeners;
|
||||
if ( newListeners == null || newListeners.length == 0 ) {
|
||||
this.listenersAsList = emptyList();
|
||||
}
|
||||
else {
|
||||
this.listenersAsList = asList( newListeners );
|
||||
}
|
||||
listeners = newListeners;
|
||||
listenersAsList = newListeners == null || newListeners.length == 0
|
||||
? emptyList()
|
||||
: asList( newListeners );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -107,7 +121,7 @@ class EventListenerGroupImpl<T> implements EventListenerGroup<T> {
|
|||
}
|
||||
|
||||
@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;
|
||||
if ( ls != null && ls.length != 0 ) {
|
||||
final U event = eventSupplier.get();
|
||||
|
@ -119,7 +133,7 @@ class EventListenerGroupImpl<T> implements EventListenerGroup<T> {
|
|||
}
|
||||
|
||||
@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;
|
||||
if ( ls != null ) {
|
||||
//noinspection ForLoopReplaceableByForEach
|
||||
|
@ -130,7 +144,7 @@ class EventListenerGroupImpl<T> implements EventListenerGroup<T> {
|
|||
}
|
||||
|
||||
@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;
|
||||
if ( ls != null ) {
|
||||
//noinspection ForLoopReplaceableByForEach
|
||||
|
@ -144,9 +158,9 @@ class EventListenerGroupImpl<T> implements EventListenerGroup<T> {
|
|||
public <R, U, RL> CompletionStage<R> fireEventOnEachListener(
|
||||
final U event,
|
||||
final Function<RL, Function<U, CompletionStage<R>>> fun) {
|
||||
CompletionStage<R> ret = COMPLETED;
|
||||
CompletionStage<R> ret = nullCompletion();
|
||||
final T[] ls = listeners;
|
||||
if ( ls != null && ls.length != 0 ) {
|
||||
if ( ls != null ) {
|
||||
for ( T listener : ls ) {
|
||||
//to preserve atomicity of the Session methods
|
||||
//call apply() from within the arg of thenCompose()
|
||||
|
@ -159,9 +173,9 @@ class EventListenerGroupImpl<T> implements EventListenerGroup<T> {
|
|||
@Override
|
||||
public <R, U, RL, X> CompletionStage<R> fireEventOnEachListener(
|
||||
U event, X param, Function<RL, BiFunction<U, X, CompletionStage<R>>> fun) {
|
||||
CompletionStage<R> ret = COMPLETED;
|
||||
CompletionStage<R> ret = nullCompletion();
|
||||
final T[] ls = listeners;
|
||||
if ( ls != null && ls.length != 0 ) {
|
||||
if ( ls != null ) {
|
||||
for ( T listener : ls ) {
|
||||
//to preserve atomicity of the Session methods
|
||||
//call apply() from within the arg of thenCompose()
|
||||
|
@ -173,9 +187,9 @@ class EventListenerGroupImpl<T> implements EventListenerGroup<T> {
|
|||
|
||||
@Override
|
||||
public <R, U, RL> CompletionStage<R> fireLazyEventOnEachListener(
|
||||
final Supplier<U> eventSupplier,
|
||||
final Function<RL, Function<U, CompletionStage<R>>> fun) {
|
||||
CompletionStage<R> ret = COMPLETED;
|
||||
Supplier<U> eventSupplier,
|
||||
Function<RL, Function<U, CompletionStage<R>>> fun) {
|
||||
CompletionStage<R> ret = nullCompletion();
|
||||
final T[] ls = listeners;
|
||||
if ( ls != null && ls.length != 0 ) {
|
||||
final U event = eventSupplier.get();
|
||||
|
@ -191,7 +205,8 @@ class EventListenerGroupImpl<T> implements EventListenerGroup<T> {
|
|||
@Override
|
||||
public void addDuplicationStrategy(DuplicationStrategy strategy) {
|
||||
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 );
|
||||
}
|
||||
|
@ -212,19 +227,17 @@ class EventListenerGroupImpl<T> implements EventListenerGroup<T> {
|
|||
|
||||
private void internalAppend(T listener) {
|
||||
prepareListener( listener );
|
||||
final T[] listenersRead = this.listeners;
|
||||
final T[] listenersRead = listeners;
|
||||
final T[] listenersWrite;
|
||||
|
||||
if ( listenersRead == null ) {
|
||||
//noinspection unchecked
|
||||
listenersWrite = (T[]) Array.newInstance( eventType.baseListenerInterface(), 1 );
|
||||
listenersWrite = createListenerArrayForWrite( 1 );
|
||||
listenersWrite[0] = listener;
|
||||
}
|
||||
else {
|
||||
final int size = listenersRead.length;
|
||||
|
||||
//noinspection unchecked
|
||||
listenersWrite = (T[]) Array.newInstance( eventType.baseListenerInterface(), size+1 );
|
||||
listenersWrite = createListenerArrayForWrite( size + 1 );
|
||||
|
||||
// first copy the existing listeners
|
||||
System.arraycopy( listenersRead, 0, listenersWrite, 0, size );
|
||||
|
@ -251,19 +264,17 @@ class EventListenerGroupImpl<T> implements EventListenerGroup<T> {
|
|||
|
||||
private void internalPrepend(T listener) {
|
||||
prepareListener( listener );
|
||||
final T[] listenersRead = this.listeners;
|
||||
final T[] listenersRead = listeners;
|
||||
final T[] listenersWrite;
|
||||
|
||||
if ( listenersRead == null ) {
|
||||
//noinspection unchecked
|
||||
listenersWrite = (T[]) Array.newInstance( eventType.baseListenerInterface(), 1 );
|
||||
listenersWrite = createListenerArrayForWrite( 1 );
|
||||
listenersWrite[0] = listener;
|
||||
}
|
||||
else {
|
||||
final int size = listenersRead.length;
|
||||
|
||||
//noinspection unchecked
|
||||
listenersWrite = (T[]) Array.newInstance( eventType.baseListenerInterface(), size+1 );
|
||||
listenersWrite = createListenerArrayForWrite( size + 1 );
|
||||
|
||||
// put the new one first
|
||||
listenersWrite[0] = listener;
|
||||
|
@ -275,13 +286,15 @@ class EventListenerGroupImpl<T> implements EventListenerGroup<T> {
|
|||
}
|
||||
|
||||
private void handleListenerAddition(T listener, Consumer<T> additionHandler) {
|
||||
final T[] listenersRead = this.listeners;
|
||||
final T[] listenersRead = listeners;
|
||||
if ( listenersRead == null ) {
|
||||
additionHandler.accept( listener );
|
||||
return;
|
||||
}
|
||||
final T[] listenersWrite = (T[]) Array.newInstance( eventType.baseListenerInterface(), listenersRead.length );
|
||||
System.arraycopy( listenersRead, 0, listenersWrite, 0, listenersRead.length );
|
||||
int size = listenersRead.length;
|
||||
|
||||
final T[] listenersWrite = createListenerArrayForWrite( size );
|
||||
System.arraycopy( listenersRead, 0, listenersWrite, 0, size );
|
||||
|
||||
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
|
||||
// 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];
|
||||
if ( debugEnabled ) {
|
||||
log.debugf(
|
||||
"Checking incoming listener [`%s`] for match against existing listener [`%s`]",
|
||||
listener,
|
||||
existingListener
|
||||
);
|
||||
log.debugf( "Checking incoming listener [`%s`] for match against existing listener [`%s`]",
|
||||
listener, existingListener );
|
||||
}
|
||||
|
||||
if ( strategy.areMatch( listener, existingListener ) ) {
|
||||
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() ) {
|
||||
case ERROR: {
|
||||
final DuplicationStrategy.Action action = strategy.getAction();
|
||||
switch (action) {
|
||||
case ERROR:
|
||||
throw new EventListenerRegistrationException( "Duplicate event listener found" );
|
||||
}
|
||||
case KEEP_ORIGINAL: {
|
||||
case KEEP_ORIGINAL:
|
||||
if ( debugEnabled ) {
|
||||
log.debugf( "Skipping listener registration (%s) : `%s`", strategy.getAction(), listener );
|
||||
log.debugf( "Skipping listener registration (%s) : `%s`",
|
||||
action, listener );
|
||||
}
|
||||
return;
|
||||
}
|
||||
case REPLACE_ORIGINAL: {
|
||||
case REPLACE_ORIGINAL:
|
||||
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 );
|
||||
|
||||
listenersWrite[i] = listener;
|
||||
}
|
||||
}
|
||||
|
||||
// we've found a match - we should return: the match action has already been applied at this point
|
||||
// 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 );
|
||||
performInjections( listener );
|
||||
additionHandler.accept( listener );
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private T[] createListenerArrayForWrite(int len) {
|
||||
return (T[]) Array.newInstance( eventType.baseListenerInterface(), len );
|
||||
}
|
||||
|
||||
private void prepareListener(T listener) {
|
||||
checkAgainstBaseInterface( listener );
|
||||
performInjections( listener );
|
||||
}
|
||||
|
||||
private void performInjections(T listener) {
|
||||
if ( listener instanceof CallbackRegistryConsumer ) {
|
||||
( (CallbackRegistryConsumer) listener ).injectCallbackRegistry( callbackRegistry );
|
||||
if ( listener instanceof CallbackRegistryConsumer consumer ) {
|
||||
consumer.injectCallbackRegistry( callbackRegistry );
|
||||
}
|
||||
|
||||
if ( listener instanceof JpaBootstrapSensitive ) {
|
||||
( (JpaBootstrapSensitive) listener ).wasJpaBootstrap( isJpaBootstrap );
|
||||
if ( listener instanceof JpaBootstrapSensitive sensitive ) {
|
||||
sensitive.wasJpaBootstrap( isJpaBootstrap );
|
||||
}
|
||||
}
|
||||
|
||||
private void checkAgainstBaseInterface(T listener) {
|
||||
if ( !eventType.baseListenerInterface().isInstance( listener ) ) {
|
||||
throw new EventListenerRegistrationException(
|
||||
"Listener did not implement expected interface [" + eventType.baseListenerInterface().getName() + "]"
|
||||
);
|
||||
throw new EventListenerRegistrationException( "Listener did not implement expected interface ["
|
||||
+ eventType.baseListenerInterface().getName() + "]" );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -372,26 +385,6 @@ class EventListenerGroupImpl<T> implements EventListenerGroup<T> {
|
|||
@Override
|
||||
@Deprecated
|
||||
public final Iterable<T> listeners() {
|
||||
return this.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 listenersAsList;
|
||||
}
|
||||
}
|
||||
);
|
||||
return duplicationStrategies;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -49,9 +49,9 @@ public interface EventListenerGroup<T> {
|
|||
/**
|
||||
* Mechanism to more finely control the notion of duplicates.
|
||||
* <p>
|
||||
* For example, say you are registering listeners for an extension library. This extension library
|
||||
* could define a "marker interface" which indicates listeners related to it and register a strategy
|
||||
* that checks against that marker interface.
|
||||
* For example, say you are registering listeners for an extension library. This
|
||||
* extension library could define a "marker interface" which indicates listeners
|
||||
* related to it and register a strategy that checks against that marker interface.
|
||||
*
|
||||
* @param strategy The duplication strategy
|
||||
*/
|
||||
|
@ -64,10 +64,11 @@ public interface EventListenerGroup<T> {
|
|||
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.
|
||||
* @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
|
||||
void clear();
|
||||
|
@ -80,57 +81,65 @@ public interface EventListenerGroup<T> {
|
|||
/**
|
||||
* Fires an event on each registered event listener of this group.
|
||||
*
|
||||
* Implementation note (performance):
|
||||
* the first argument is a supplier so that events can avoid being created when no listener is registered.
|
||||
* the second argument is specifically designed to avoid needing a capturing lambda.
|
||||
* @implNote The first argument is a supplier so that events can avoid being created
|
||||
* when no listener is registered; The second argument is specifically
|
||||
* designed to avoid needing a capturing lambda.
|
||||
*
|
||||
* @param <U> the kind of event
|
||||
*/
|
||||
@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}}:
|
||||
* useful when there is no need to lazily initialize the event.
|
||||
* Similar as {@link #fireLazyEventOnEachListener(Supplier, BiConsumer)} except it
|
||||
* doesn't use a {{@link Supplier}}. Useful when there is no need to lazily initialize
|
||||
* the event.
|
||||
*
|
||||
* @param <U> the kind of event
|
||||
*/
|
||||
@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
|
||||
* to the consumer; our code based occasionally needs a third parameter: having this additional variant
|
||||
* allows using the optimal iteration more extensively and reduce allocations.
|
||||
* Similar to {@link #fireEventOnEachListener(Object, BiConsumer)}, but allows passing
|
||||
* a third parameter to the consumer; our code based occasionally needs a third parameter:
|
||||
* having this additional variant allows using the optimal iteration more extensively and
|
||||
* reduce allocations.
|
||||
*/
|
||||
@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
|
||||
* processing of the same event on each Reactive Listener, and returns a {@link CompletionStage} of type R.
|
||||
* The various generic types allow using this for each concrete event type and flexible return types.
|
||||
* <p>Used by Hibernate Reactive</p>
|
||||
* Similar to {@link #fireEventOnEachListener(Object, BiConsumer)}, but Reactive friendly:
|
||||
* it chains processing of the same event on each Reactive Listener, and returns a
|
||||
* {@link CompletionStage} of type R. The various generic types allow using this for each
|
||||
* concrete event type and flexible return types.
|
||||
* <p>
|
||||
* <em>Used by Hibernate Reactive</em>
|
||||
*
|
||||
* @param event The event being fired
|
||||
* @param fun The function combining each event listener with the event
|
||||
* @param <R> the return type of the returned CompletionStage
|
||||
* @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.
|
||||
*/
|
||||
@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
|
||||
* processing of the same event on each Reactive Listener, and returns a {@link CompletionStage} of type R.
|
||||
* The various generic types allow using this for each concrete event type and flexible return types.
|
||||
* <p>Used by Hibernate Reactive</p>
|
||||
* Similar to {@link #fireEventOnEachListener(Object, Object, EventActionWithParameter)},
|
||||
* but Reactive friendly: it chains processing of the same event on each Reactive Listener,
|
||||
* and returns a {@link CompletionStage} of type R. The various generic types allow using
|
||||
* this for each concrete event type and flexible return types.
|
||||
* <p>
|
||||
* <em>Used by Hibernate Reactive</em>
|
||||
*
|
||||
* @param event The event being fired
|
||||
* @param fun The function combining each event listener with the event
|
||||
* @param <R> the return type of the returned CompletionStage
|
||||
* @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
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* Similar to {@link #fireLazyEventOnEachListener(Supplier, BiConsumer)}, but Reactive friendly: it chains
|
||||
* processing of the same event on each Reactive Listener, and returns a {@link CompletionStage} of type R.
|
||||
* The various generic types allow using this for each concrete event type and flexible return types.
|
||||
* <p>This variant expects a Supplier of the event, rather than the event directly; this is 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>
|
||||
* <p>Used by Hibernate Reactive</p>
|
||||
* Similar to {@link #fireLazyEventOnEachListener(Supplier, BiConsumer)}, but Reactive
|
||||
* friendly: it chains processing of the same event on each Reactive Listener, and returns
|
||||
* a {@link CompletionStage} of type R. The various generic types allow using this for
|
||||
* each concrete event type and flexible return types.
|
||||
* <p>
|
||||
* This variant expects a Supplier of the event, rather than the event directly; this is
|
||||
* 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 fun The function combining each event listener with the event
|
||||
* @param <R> the return type of the returned CompletionStage
|
||||
* @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.
|
||||
*/
|
||||
@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