1717
1818package org .glassfish .kernel .event ;
1919
20- import java .lang .reflect .Method ;
2120import java .util .Arrays ;
2221import java .util .Map ;
22+ import java .util .concurrent .ConcurrentHashMap ;
2323import java .util .concurrent .ConcurrentSkipListMap ;
2424import java .util .concurrent .ExecutorService ;
2525import java .util .concurrent .Executors ;
2626import java .util .concurrent .ThreadFactory ;
2727import java .util .concurrent .atomic .AtomicLong ;
28- import java .util .logging .Level ;
2928import java .util .logging .Logger ;
3029
3130import org .glassfish .api .event .EventListener ;
3736import org .glassfish .hk2 .api .PostConstruct ;
3837import org .glassfish .kernel .KernelLoggerInfo ;
3938
39+ import static java .util .logging .Level .SEVERE ;
40+ import static java .util .logging .Level .WARNING ;
41+
4042/**
4143 * Simple implementation of the events dispatching facility.
4244 *
@@ -51,7 +53,8 @@ public class EventsImpl implements Events, PostConstruct {
5153 /**
5254 * Use skip list based map to preserve listeners in registration order.
5355 */
54- final Map <Listener , EventMatcher > listeners = new ConcurrentSkipListMap <>();
56+ final Map <Listener , EventMatcher > listenersBySequence = new ConcurrentSkipListMap <>();
57+ final Map <EventListener , Listener > listenersByIdentity = new ConcurrentHashMap <>();
5558
5659 private ExecutorService executor ;
5760
@@ -70,22 +73,43 @@ public void postConstruct() {
7073 @ Override
7174 public void register (EventListener listener ) {
7275 try {
73- Method eventMethod = listener .getClass ().getMethod ("event" , Event .class );
74- RestrictTo [] restrictTo = eventMethod .getParameters ()[0 ].getAnnotationsByType (RestrictTo .class );
75- EventTypes <?>[] eventTypes = Arrays .stream (restrictTo )
76- .map (restrict -> EventTypes .create (restrict .value ())).toArray (EventTypes []::new );
77- listeners .putIfAbsent (new Listener (listener , sequenceGenerator .getAndIncrement ()), new EventMatcher (eventTypes ));
76+ RestrictTo [] restrictTo =
77+ listener .getClass ()
78+ .getMethod ("event" , Event .class )
79+ .getParameters ()[0 ]
80+ .getAnnotationsByType (RestrictTo .class );
81+
82+ listenersByIdentity .computeIfAbsent (listener , e -> {
83+
84+ Listener listenerWrapperWithSeq = new Listener (listener , sequenceGenerator .getAndIncrement ());
85+
86+ EventMatcher eventMatcher = new EventMatcher (
87+ Arrays .stream (restrictTo )
88+ .map (restrict -> EventTypes .create (restrict .value ()))
89+ .toArray (EventTypes []::new ));
90+
91+ listenersBySequence .put (
92+ listenerWrapperWithSeq ,
93+ eventMatcher );
94+
95+ return listenerWrapperWithSeq ;
96+ });
97+
98+
7899 } catch (Throwable t ) {
79- // We need to catch Throwable, otherwise we can server not to
80- // shutdown when the following happens:
100+ // We need to catch Throwable, otherwise we can not
101+ // shutdown the server when the following happens:
102+ //
81103 // Assume a bundle which has registered an event listener
82104 // has been uninstalled without unregistering the listener.
105+ //
83106 // listener.getClass() refers to a class of such an uninstalled
84- // bundle. If framework has been refreshed, then the
107+ // bundle. If the framework has been refreshed, then the
85108 // classloader can't be used further to load any classes.
109+ //
86110 // As a result, an exception like NoClassDefFoundError is thrown
87111 // from getMethod.
88- LOG .log (Level . SEVERE , KernelLoggerInfo .exceptionRegisterEventListener , t );
112+ LOG .log (SEVERE , KernelLoggerInfo .exceptionRegisterEventListener , t );
89113 }
90114 }
91115
@@ -96,28 +120,32 @@ public void send(final Event<?> event) {
96120
97121 @ Override
98122 public void send (final Event <?> event , boolean asynchronously ) {
99- for (Map . Entry < Listener , EventMatcher > entry : listeners .entrySet ()) {
100- EventMatcher matcher = entry . getValue ();
123+ for (var entry : listenersBySequence .entrySet ()) {
124+
101125 // Check if the listener is interested with his event.
102- if (matcher .matches (event )) {
126+ if (entry .getValue ().matches (event )) {
127+
103128 Listener listener = entry .getKey ();
129+
104130 if (asynchronously ) {
131+ // Process Async
105132 executor .submit (() -> {
106133 try {
107134 listener .event (event );
108135 } catch (Throwable t ) {
109- LOG .log (Level . WARNING , KernelLoggerInfo .exceptionDispatchEvent , t );
136+ LOG .log (WARNING , KernelLoggerInfo .exceptionDispatchEvent , t );
110137 }
111138 });
112139 } else {
140+ // Process sync
113141 try {
114142 listener .event (event );
115143 } catch (DeploymentException e ) {
116144 // When synchronous listener throws DeploymentException
117145 // we re-throw the exception to abort the deployment
118146 throw e ;
119147 } catch (Throwable t ) {
120- LOG .log (Level . WARNING , KernelLoggerInfo .exceptionDispatchEvent , t );
148+ LOG .log (WARNING , KernelLoggerInfo .exceptionDispatchEvent , t );
121149 }
122150 }
123151 }
@@ -126,7 +154,12 @@ public void send(final Event<?> event, boolean asynchronously) {
126154
127155 @ Override
128156 public boolean unregister (EventListener listener ) {
129- return listeners .remove (new Listener (listener )) != null ;
157+ Listener listenerWrapperWithSeq = listenersByIdentity .remove (listener );
158+ if (listenerWrapperWithSeq == null ) {
159+ return false ;
160+ }
161+
162+ return listenersBySequence .remove (listenerWrapperWithSeq ) != null ;
130163 }
131164
132165 /**
@@ -158,23 +191,26 @@ EventListener unwrap() {
158191
159192 @ Override
160193 public boolean equals (Object obj ) {
161- if (obj == this ) {
162- return true ;
163- }
164- if (!(obj instanceof Listener )) {
165- return false ;
166- }
167- return eventListener .equals (((Listener ) obj ).eventListener );
194+ return
195+ obj instanceof Listener listener &&
196+ this .eventListener == listener .eventListener ;
168197 }
169198
170199 @ Override
171200 public int hashCode () {
172- return eventListener . hashCode ( );
201+ return System . identityHashCode ( eventListener );
173202 }
174203
175204 @ Override
176205 public int compareTo (Listener listener ) {
177- return Long .compare (sequenceNumber , listener .sequenceNumber );
206+ // Treat the same underlying listener as the SAME KEY
207+ if (this .eventListener == listener .eventListener ) {
208+ // Identity
209+ return 0 ;
210+ }
211+
212+ // otherwise keep registration order via sequence
213+ return Long .compare (this .sequenceNumber , listener .sequenceNumber );
178214 }
179215 }
180216
0 commit comments