7
7
package org .hibernate .event .service .internal ;
8
8
9
9
import java .lang .reflect .Array ;
10
- import java .util .Collections ;
11
10
import java .util .LinkedHashSet ;
12
11
import java .util .List ;
13
12
import java .util .Set ;
32
31
33
32
import static java .util .Arrays .asList ;
34
33
import static java .util .Collections .emptyList ;
34
+ import static java .util .Collections .singleton ;
35
+ import static java .util .concurrent .CompletableFuture .completedFuture ;
35
36
36
37
/**
37
38
* Standard EventListenerGroup implementation
42
43
class EventListenerGroupImpl <T > implements EventListenerGroup <T > {
43
44
44
45
private static final Logger log = Logger .getLogger ( EventListenerGroupImpl .class );
45
- private static final Set <DuplicationStrategy > DEFAULT_DUPLICATION_STRATEGIES = Collections .unmodifiableSet ( makeDefaultDuplicationStrategy () );
46
- private static final CompletableFuture COMPLETED = CompletableFuture .completedFuture ( null );
46
+
47
+ private static final DuplicationStrategy DEFAULT_DUPLICATION_STRATEGY =
48
+ new DuplicationStrategy () {
49
+ @ Override
50
+ public boolean areMatch (Object listener , Object original ) {
51
+ return listener .getClass ().equals ( original .getClass () );
52
+ }
53
+ @ Override
54
+ public Action getAction () {
55
+ return Action .ERROR ;
56
+ }
57
+ };
58
+ private static final Set <DuplicationStrategy > DEFAULT_DUPLICATION_STRATEGIES =
59
+ singleton ( DEFAULT_DUPLICATION_STRATEGY );
60
+
61
+ private static final CompletableFuture <?> COMPLETED = completedFuture ( null );
62
+ @ SuppressWarnings ("unchecked" )
63
+ private static <R > CompletableFuture <R > nullCompletion () {
64
+ return (CompletableFuture <R >) COMPLETED ;
65
+ }
47
66
48
67
private final EventType <T > eventType ;
49
68
private final CallbackRegistry callbackRegistry ;
@@ -56,10 +75,7 @@ class EventListenerGroupImpl<T> implements EventListenerGroup<T> {
56
75
private volatile T [] listeners = null ;
57
76
private volatile List <T > listenersAsList = emptyList ();
58
77
59
- public EventListenerGroupImpl (
60
- EventType <T > eventType ,
61
- CallbackRegistry callbackRegistry ,
62
- boolean isJpaBootstrap ) {
78
+ public EventListenerGroupImpl (EventType <T > eventType , CallbackRegistry callbackRegistry , boolean isJpaBootstrap ) {
63
79
this .eventType = eventType ;
64
80
this .callbackRegistry = callbackRegistry ;
65
81
this .isJpaBootstrap = isJpaBootstrap ;
@@ -83,7 +99,8 @@ public int count() {
83
99
84
100
@ Override
85
101
public void clear () {
86
- //Odd semantics: we're expected (for backwards compatibility) to also clear the default DuplicationStrategy.
102
+ //Odd semantics: we're expected (for backwards compatibility)
103
+ // to also clear the default DuplicationStrategy.
87
104
duplicationStrategies = new LinkedHashSet <>();
88
105
setListeners ( null );
89
106
}
@@ -92,13 +109,10 @@ public void clear() {
92
109
// ensure consistency between the two fields by delegating any mutation to both
93
110
// fields to this method.
94
111
private synchronized void setListeners (T [] newListeners ) {
95
- this .listeners = newListeners ;
96
- if ( newListeners == null || newListeners .length == 0 ) {
97
- this .listenersAsList = emptyList ();
98
- }
99
- else {
100
- this .listenersAsList = asList ( newListeners );
101
- }
112
+ listeners = newListeners ;
113
+ listenersAsList = newListeners == null || newListeners .length == 0
114
+ ? emptyList ()
115
+ : asList ( newListeners );
102
116
}
103
117
104
118
@ Override
@@ -107,7 +121,7 @@ public void clearListeners() {
107
121
}
108
122
109
123
@ Override
110
- public final <U > void fireLazyEventOnEachListener (final Supplier <U > eventSupplier , final BiConsumer <T ,U > actionOnEvent ) {
124
+ public final <U > void fireLazyEventOnEachListener (Supplier <U > eventSupplier , BiConsumer <T ,U > actionOnEvent ) {
111
125
final T [] ls = listeners ;
112
126
if ( ls != null && ls .length != 0 ) {
113
127
final U event = eventSupplier .get ();
@@ -119,7 +133,7 @@ public final <U> void fireLazyEventOnEachListener(final Supplier<U> eventSupplie
119
133
}
120
134
121
135
@ Override
122
- public final <U > void fireEventOnEachListener (final U event , final BiConsumer <T ,U > actionOnEvent ) {
136
+ public final <U > void fireEventOnEachListener (U event , BiConsumer <T ,U > actionOnEvent ) {
123
137
final T [] ls = listeners ;
124
138
if ( ls != null ) {
125
139
//noinspection ForLoopReplaceableByForEach
@@ -130,7 +144,7 @@ public final <U> void fireEventOnEachListener(final U event, final BiConsumer<T,
130
144
}
131
145
132
146
@ Override
133
- public <U ,X > void fireEventOnEachListener (final U event , final X parameter , final EventActionWithParameter <T , U , X > actionOnEvent ) {
147
+ public <U ,X > void fireEventOnEachListener (U event , X parameter , EventActionWithParameter <T , U , X > actionOnEvent ) {
134
148
final T [] ls = listeners ;
135
149
if ( ls != null ) {
136
150
//noinspection ForLoopReplaceableByForEach
@@ -144,9 +158,9 @@ public <U,X> void fireEventOnEachListener(final U event, final X parameter, fina
144
158
public <R , U , RL > CompletionStage <R > fireEventOnEachListener (
145
159
final U event ,
146
160
final Function <RL , Function <U , CompletionStage <R >>> fun ) {
147
- CompletionStage <R > ret = COMPLETED ;
161
+ CompletionStage <R > ret = nullCompletion () ;
148
162
final T [] ls = listeners ;
149
- if ( ls != null && ls . length != 0 ) {
163
+ if ( ls != null ) {
150
164
for ( T listener : ls ) {
151
165
//to preserve atomicity of the Session methods
152
166
//call apply() from within the arg of thenCompose()
@@ -159,9 +173,9 @@ public <R, U, RL> CompletionStage<R> fireEventOnEachListener(
159
173
@ Override
160
174
public <R , U , RL , X > CompletionStage <R > fireEventOnEachListener (
161
175
U event , X param , Function <RL , BiFunction <U , X , CompletionStage <R >>> fun ) {
162
- CompletionStage <R > ret = COMPLETED ;
176
+ CompletionStage <R > ret = nullCompletion () ;
163
177
final T [] ls = listeners ;
164
- if ( ls != null && ls . length != 0 ) {
178
+ if ( ls != null ) {
165
179
for ( T listener : ls ) {
166
180
//to preserve atomicity of the Session methods
167
181
//call apply() from within the arg of thenCompose()
@@ -173,9 +187,9 @@ public <R, U, RL, X> CompletionStage<R> fireEventOnEachListener(
173
187
174
188
@ Override
175
189
public <R , U , RL > CompletionStage <R > fireLazyEventOnEachListener (
176
- final Supplier <U > eventSupplier ,
177
- final Function <RL , Function <U , CompletionStage <R >>> fun ) {
178
- CompletionStage <R > ret = COMPLETED ;
190
+ Supplier <U > eventSupplier ,
191
+ Function <RL , Function <U , CompletionStage <R >>> fun ) {
192
+ CompletionStage <R > ret = nullCompletion () ;
179
193
final T [] ls = listeners ;
180
194
if ( ls != null && ls .length != 0 ) {
181
195
final U event = eventSupplier .get ();
@@ -191,7 +205,8 @@ public <R, U, RL> CompletionStage<R> fireLazyEventOnEachListener(
191
205
@ Override
192
206
public void addDuplicationStrategy (DuplicationStrategy strategy ) {
193
207
if ( duplicationStrategies == DEFAULT_DUPLICATION_STRATEGIES ) {
194
- duplicationStrategies = makeDefaultDuplicationStrategy ();
208
+ // At minimum make sure we do not register the same exact listener class multiple times.
209
+ duplicationStrategies = new LinkedHashSet <>( DEFAULT_DUPLICATION_STRATEGIES );
195
210
}
196
211
duplicationStrategies .add ( strategy );
197
212
}
@@ -212,19 +227,17 @@ public final void appendListeners(T... listeners) {
212
227
213
228
private void internalAppend (T listener ) {
214
229
prepareListener ( listener );
215
- final T [] listenersRead = this . listeners ;
230
+ final T [] listenersRead = listeners ;
216
231
final T [] listenersWrite ;
217
232
218
233
if ( listenersRead == null ) {
219
- //noinspection unchecked
220
- listenersWrite = (T []) Array .newInstance ( eventType .baseListenerInterface (), 1 );
234
+ listenersWrite = createListenerArrayForWrite ( 1 );
221
235
listenersWrite [0 ] = listener ;
222
236
}
223
237
else {
224
238
final int size = listenersRead .length ;
225
239
226
- //noinspection unchecked
227
- listenersWrite = (T []) Array .newInstance ( eventType .baseListenerInterface (), size +1 );
240
+ listenersWrite = createListenerArrayForWrite ( size + 1 );
228
241
229
242
// first copy the existing listeners
230
243
System .arraycopy ( listenersRead , 0 , listenersWrite , 0 , size );
@@ -251,19 +264,17 @@ public final void prependListeners(T... listeners) {
251
264
252
265
private void internalPrepend (T listener ) {
253
266
prepareListener ( listener );
254
- final T [] listenersRead = this . listeners ;
267
+ final T [] listenersRead = listeners ;
255
268
final T [] listenersWrite ;
256
269
257
270
if ( listenersRead == null ) {
258
- //noinspection unchecked
259
- listenersWrite = (T []) Array .newInstance ( eventType .baseListenerInterface (), 1 );
271
+ listenersWrite = createListenerArrayForWrite ( 1 );
260
272
listenersWrite [0 ] = listener ;
261
273
}
262
274
else {
263
275
final int size = listenersRead .length ;
264
276
265
- //noinspection unchecked
266
- listenersWrite = (T []) Array .newInstance ( eventType .baseListenerInterface (), size +1 );
277
+ listenersWrite = createListenerArrayForWrite ( size + 1 );
267
278
268
279
// put the new one first
269
280
listenersWrite [0 ] = listener ;
@@ -275,13 +286,15 @@ private void internalPrepend(T listener) {
275
286
}
276
287
277
288
private void handleListenerAddition (T listener , Consumer <T > additionHandler ) {
278
- final T [] listenersRead = this . listeners ;
289
+ final T [] listenersRead = listeners ;
279
290
if ( listenersRead == null ) {
280
291
additionHandler .accept ( listener );
281
292
return ;
282
293
}
283
- final T [] listenersWrite = (T []) Array .newInstance ( eventType .baseListenerInterface (), listenersRead .length );
284
- System .arraycopy ( listenersRead , 0 , listenersWrite , 0 , listenersRead .length );
294
+ int size = listenersRead .length ;
295
+
296
+ final T [] listenersWrite = createListenerArrayForWrite ( size );
297
+ System .arraycopy ( listenersRead , 0 , listenersWrite , 0 , size );
285
298
286
299
final boolean debugEnabled = log .isDebugEnabled ();
287
300
@@ -292,39 +305,36 @@ private void handleListenerAddition(T listener, Consumer<T> additionHandler) {
292
305
// strategy's action. Control it returned immediately after applying the action
293
306
// on match - meaning no further strategies are checked...
294
307
295
- for ( int i = 0 ; i < listenersRead . length ; i ++ ) {
308
+ for ( int i = 0 ; i < size ; i ++ ) {
296
309
final T existingListener = listenersRead [i ];
297
310
if ( debugEnabled ) {
298
- log .debugf (
299
- "Checking incoming listener [`%s`] for match against existing listener [`%s`]" ,
300
- listener ,
301
- existingListener
302
- );
311
+ log .debugf ( "Checking incoming listener [`%s`] for match against existing listener [`%s`]" ,
312
+ listener , existingListener );
303
313
}
304
314
305
315
if ( strategy .areMatch ( listener , existingListener ) ) {
306
316
if ( debugEnabled ) {
307
- log .debugf ( "Found listener match between `%s` and `%s`" , listener , existingListener );
317
+ log .debugf ( "Found listener match between `%s` and `%s`" ,
318
+ listener , existingListener );
308
319
}
309
320
310
- switch ( strategy .getAction () ) {
311
- case ERROR : {
321
+ final DuplicationStrategy .Action action = strategy .getAction ();
322
+ switch (action ) {
323
+ case ERROR :
312
324
throw new EventListenerRegistrationException ( "Duplicate event listener found" );
313
- }
314
- case KEEP_ORIGINAL : {
325
+ case KEEP_ORIGINAL :
315
326
if ( debugEnabled ) {
316
- log .debugf ( "Skipping listener registration (%s) : `%s`" , strategy .getAction (), listener );
327
+ log .debugf ( "Skipping listener registration (%s) : `%s`" ,
328
+ action , listener );
317
329
}
318
330
return ;
319
- }
320
- case REPLACE_ORIGINAL : {
331
+ case REPLACE_ORIGINAL :
321
332
if ( debugEnabled ) {
322
- log .debugf ( "Replacing listener registration (%s) : `%s` -> `%s`" , strategy .getAction (), existingListener , listener );
333
+ log .debugf ( "Replacing listener registration (%s) : `%s` -> `%s`" ,
334
+ action , existingListener , listener );
323
335
}
324
336
prepareListener ( listener );
325
-
326
337
listenersWrite [i ] = listener ;
327
- }
328
338
}
329
339
330
340
// we've found a match - we should return: the match action has already been applied at this point
@@ -335,32 +345,35 @@ private void handleListenerAddition(T listener, Consumer<T> additionHandler) {
335
345
}
336
346
}
337
347
338
- // we did not find any match.. add it
348
+ // we did not find any match, add it
339
349
checkAgainstBaseInterface ( listener );
340
350
performInjections ( listener );
341
351
additionHandler .accept ( listener );
342
352
}
343
353
354
+ @ SuppressWarnings ("unchecked" )
355
+ private T [] createListenerArrayForWrite (int len ) {
356
+ return (T []) Array .newInstance ( eventType .baseListenerInterface (), len );
357
+ }
358
+
344
359
private void prepareListener (T listener ) {
345
360
checkAgainstBaseInterface ( listener );
346
361
performInjections ( listener );
347
362
}
348
363
349
364
private void performInjections (T listener ) {
350
- if ( listener instanceof CallbackRegistryConsumer ) {
351
- ( ( CallbackRegistryConsumer ) listener ) .injectCallbackRegistry ( callbackRegistry );
365
+ if ( listener instanceof CallbackRegistryConsumer consumer ) {
366
+ consumer .injectCallbackRegistry ( callbackRegistry );
352
367
}
353
-
354
- if ( listener instanceof JpaBootstrapSensitive ) {
355
- ( (JpaBootstrapSensitive ) listener ).wasJpaBootstrap ( isJpaBootstrap );
368
+ if ( listener instanceof JpaBootstrapSensitive sensitive ) {
369
+ sensitive .wasJpaBootstrap ( isJpaBootstrap );
356
370
}
357
371
}
358
372
359
373
private void checkAgainstBaseInterface (T listener ) {
360
374
if ( !eventType .baseListenerInterface ().isInstance ( listener ) ) {
361
- throw new EventListenerRegistrationException (
362
- "Listener did not implement expected interface [" + eventType .baseListenerInterface ().getName () + "]"
363
- );
375
+ throw new EventListenerRegistrationException ( "Listener did not implement expected interface ["
376
+ + eventType .baseListenerInterface ().getName () + "]" );
364
377
}
365
378
}
366
379
@@ -372,26 +385,6 @@ private void checkAgainstBaseInterface(T listener) {
372
385
@ Override
373
386
@ Deprecated
374
387
public final Iterable <T > listeners () {
375
- return this .listenersAsList ;
376
- }
377
-
378
- private static Set <DuplicationStrategy > makeDefaultDuplicationStrategy () {
379
- final Set <DuplicationStrategy > duplicationStrategies = new LinkedHashSet <>();
380
- duplicationStrategies .add (
381
- // At minimum make sure we do not register the same exact listener class multiple times.
382
- new DuplicationStrategy () {
383
- @ Override
384
- public boolean areMatch (Object listener , Object original ) {
385
- return listener .getClass ().equals ( original .getClass () );
386
- }
387
-
388
- @ Override
389
- public Action getAction () {
390
- return Action .ERROR ;
391
- }
392
- }
393
- );
394
- return duplicationStrategies ;
388
+ return listenersAsList ;
395
389
}
396
-
397
390
}
0 commit comments