1
18
19 package io.undertow.servlet.core;
20
21 import io.undertow.servlet.UndertowServletLogger;
22
23 import javax.servlet.ServletContext;
24 import javax.servlet.ServletContextAttributeEvent;
25 import javax.servlet.ServletContextAttributeListener;
26 import javax.servlet.ServletContextEvent;
27 import javax.servlet.ServletContextListener;
28 import javax.servlet.ServletException;
29 import javax.servlet.ServletRequest;
30 import javax.servlet.ServletRequestAttributeEvent;
31 import javax.servlet.ServletRequestAttributeListener;
32 import javax.servlet.ServletRequestEvent;
33 import javax.servlet.ServletRequestListener;
34 import javax.servlet.http.HttpServletRequest;
35 import javax.servlet.http.HttpSession;
36 import javax.servlet.http.HttpSessionAttributeListener;
37 import javax.servlet.http.HttpSessionBindingEvent;
38 import javax.servlet.http.HttpSessionEvent;
39 import javax.servlet.http.HttpSessionIdListener;
40 import javax.servlet.http.HttpSessionListener;
41 import java.util.ArrayList;
42 import java.util.List;
43
44 import static io.undertow.servlet.core.ApplicationListeners.ListenerState.DECLARED_LISTENER;
45 import static io.undertow.servlet.core.ApplicationListeners.ListenerState.PROGRAMATIC_LISTENER;
46
47
57 public class ApplicationListeners implements Lifecycle {
58
59
60 private static final ManagedListener[] EMPTY = {};
61
62 private static final Class[] LISTENER_CLASSES = {ServletContextListener.class,
63 ServletContextAttributeListener.class,
64 ServletRequestListener.class,
65 ServletRequestAttributeListener.class,
66 javax.servlet.http.HttpSessionListener.class,
67 javax.servlet.http.HttpSessionAttributeListener.class,
68 HttpSessionIdListener.class};
69
70 private static final ThreadLocal<ListenerState> IN_PROGRAMATIC_SC_LISTENER_INVOCATION = new ThreadLocal<ListenerState>() {
71 @Override
72 protected ListenerState initialValue() {
73 return ListenerState.NO_LISTENER;
74 }
75 };
76
77 private ServletContext servletContext;
78 private final List<ManagedListener> allListeners = new ArrayList<>();
79 private ManagedListener[] servletContextListeners;
80 private ManagedListener[] servletContextAttributeListeners;
81 private ManagedListener[] servletRequestListeners;
82 private ManagedListener[] servletRequestAttributeListeners;
83 private ManagedListener[] httpSessionListeners;
84 private ManagedListener[] httpSessionAttributeListeners;
85 private ManagedListener[] httpSessionIdListeners;
86 private volatile boolean started = false;
87
88 public ApplicationListeners(final List<ManagedListener> allListeners, final ServletContext servletContext) {
89 this.servletContext = servletContext;
90 servletContextListeners = EMPTY;
91 servletContextAttributeListeners = EMPTY;
92 servletRequestListeners = EMPTY;
93 servletRequestAttributeListeners = EMPTY;
94 httpSessionListeners = EMPTY;
95 httpSessionAttributeListeners = EMPTY;
96 httpSessionIdListeners = EMPTY;
97 for (final ManagedListener listener : allListeners) {
98 addListener(listener);
99 }
100 }
101
102 public void addListener(final ManagedListener listener) {
103 if (ServletContextListener.class.isAssignableFrom(listener.getListenerInfo().getListenerClass())) {
104 ManagedListener[] old = servletContextListeners;
105 servletContextListeners = new ManagedListener[old.length + 1];
106 System.arraycopy(old, 0, servletContextListeners, 0, old.length);
107 servletContextListeners[old.length] = listener;
108 }
109 if (ServletContextAttributeListener.class.isAssignableFrom(listener.getListenerInfo().getListenerClass())) {
110
111 ManagedListener[] old = servletContextAttributeListeners;
112 servletContextAttributeListeners = new ManagedListener[old.length + 1];
113 System.arraycopy(old, 0, servletContextAttributeListeners, 0, old.length);
114 servletContextAttributeListeners[old.length] = listener;
115 }
116 if (ServletRequestListener.class.isAssignableFrom(listener.getListenerInfo().getListenerClass())) {
117 ManagedListener[] old = servletRequestListeners;
118 servletRequestListeners = new ManagedListener[old.length + 1];
119 System.arraycopy(old, 0, servletRequestListeners, 0, old.length);
120 servletRequestListeners[old.length] = listener;
121 }
122 if (ServletRequestAttributeListener.class.isAssignableFrom(listener.getListenerInfo().getListenerClass())) {
123 ManagedListener[] old = servletRequestAttributeListeners;
124 servletRequestAttributeListeners = new ManagedListener[old.length + 1];
125 System.arraycopy(old, 0, servletRequestAttributeListeners, 0, old.length);
126 servletRequestAttributeListeners[old.length] = listener;
127 }
128 if (HttpSessionListener.class.isAssignableFrom(listener.getListenerInfo().getListenerClass())) {
129 ManagedListener[] old = httpSessionListeners;
130 httpSessionListeners = new ManagedListener[old.length + 1];
131 System.arraycopy(old, 0, httpSessionListeners, 0, old.length);
132 httpSessionListeners[old.length] = listener;
133 }
134 if (HttpSessionAttributeListener.class.isAssignableFrom(listener.getListenerInfo().getListenerClass())) {
135 ManagedListener[] old = httpSessionAttributeListeners;
136 httpSessionAttributeListeners = new ManagedListener[old.length + 1];
137 System.arraycopy(old, 0, httpSessionAttributeListeners, 0, old.length);
138 httpSessionAttributeListeners[old.length] = listener;
139 }
140 if (HttpSessionIdListener.class.isAssignableFrom(listener.getListenerInfo().getListenerClass())) {
141 ManagedListener[] old = httpSessionIdListeners;
142 httpSessionIdListeners = new ManagedListener[old.length + 1];
143 System.arraycopy(old, 0, httpSessionIdListeners, 0, old.length);
144 httpSessionIdListeners[old.length] = listener;
145 }
146 this.allListeners.add(listener);
147 if(started) {
148 try {
149 listener.start();
150 } catch (ServletException e) {
151 throw new RuntimeException(e);
152 }
153 }
154 }
155
156 public void start() throws ServletException {
157 started = true;
158 for (ManagedListener listener : allListeners) {
159 listener.start();
160 }
161 }
162
163 public void stop() {
164 if (started) {
165 started = false;
166 for (final ManagedListener listener : allListeners) {
167 listener.stop();
168 }
169 }
170 }
171
172 @Override
173 public boolean isStarted() {
174 return started;
175 }
176
177 public void contextInitialized() {
178 if(!started) {
179 return;
180 }
181
182 final ServletContextEvent event = new ServletContextEvent(servletContext);
183 for (int i = 0; i < servletContextListeners.length; ++i) {
184 ManagedListener listener = servletContextListeners[i];
185 IN_PROGRAMATIC_SC_LISTENER_INVOCATION.set(listener.isProgramatic() ? PROGRAMATIC_LISTENER : DECLARED_LISTENER);
186 try {
187 this.<ServletContextListener>get(listener).contextInitialized(event);
188 } finally {
189 IN_PROGRAMATIC_SC_LISTENER_INVOCATION.remove();
190 }
191 }
192 }
193
194 public void contextDestroyed() {
195 if(!started) {
196 return;
197 }
198 final ServletContextEvent event = new ServletContextEvent(servletContext);
199 for (int i = servletContextListeners.length - 1; i >= 0; --i) {
200 ManagedListener listener = servletContextListeners[i];
201 try {
202 this.<ServletContextListener>get(listener).contextDestroyed(event);
203 } catch (Throwable t) {
204 UndertowServletLogger.REQUEST_LOGGER.errorInvokingListener("contextDestroyed", listener.getListenerInfo().getListenerClass(), t);
205 }
206 }
207 }
208
209 public void servletContextAttributeAdded(final String name, final Object value) {
210 if(!started) {
211 return;
212 }
213 final ServletContextAttributeEvent sre = new ServletContextAttributeEvent(servletContext, name, value);
214 for (int i = 0; i < servletContextAttributeListeners.length; ++i) {
215 this.<ServletContextAttributeListener>get(servletContextAttributeListeners[i]).attributeAdded(sre);
216 }
217 }
218
219 public void servletContextAttributeRemoved(final String name, final Object value) {
220 if(!started) {
221 return;
222 }
223 final ServletContextAttributeEvent sre = new ServletContextAttributeEvent(servletContext, name, value);
224 for (int i = 0; i < servletContextAttributeListeners.length; ++i) {
225 this.<ServletContextAttributeListener>get(servletContextAttributeListeners[i]).attributeRemoved(sre);
226 }
227 }
228
229 public void servletContextAttributeReplaced(final String name, final Object value) {
230 if(!started) {
231 return;
232 }
233 final ServletContextAttributeEvent sre = new ServletContextAttributeEvent(servletContext, name, value);
234 for (int i = 0; i < servletContextAttributeListeners.length; ++i) {
235 this.<ServletContextAttributeListener>get(servletContextAttributeListeners[i]).attributeReplaced(sre);
236 }
237 }
238
239 public void requestInitialized(final ServletRequest request) {
240 if(!started) {
241 return;
242 }
243 if(servletRequestListeners.length > 0) {
244 int i = 0;
245 final ServletRequestEvent sre = new ServletRequestEvent(servletContext, request);
246 try {
247 for (; i < servletRequestListeners.length; ++i) {
248 this.<ServletRequestListener>get(servletRequestListeners[i]).requestInitialized(sre);
249 }
250 } catch (RuntimeException e) {
251 UndertowServletLogger.REQUEST_LOGGER.errorInvokingListener("requestInitialized", servletRequestListeners[i].getListenerInfo().getListenerClass(), e);
252 for (; i >= 0; i--) {
253 try {
254 this.<ServletRequestListener>get(servletRequestListeners[i]).requestDestroyed(sre);
255 } catch (Throwable t) {
256 UndertowServletLogger.REQUEST_LOGGER.errorInvokingListener("requestDestroyed", servletRequestListeners[i].getListenerInfo().getListenerClass(), e);
257 }
258 }
259 throw e;
260 }
261 }
262 }
263
264 public void requestDestroyed(final ServletRequest request) {
265 if(!started) {
266 return;
267 }
268 if(servletRequestListeners.length > 0) {
269 final ServletRequestEvent sre = new ServletRequestEvent(servletContext, request);
270 for (int i = servletRequestListeners.length - 1; i >= 0; --i) {
271 ManagedListener listener = servletRequestListeners[i];
272 try {
273 this.<ServletRequestListener>get(listener).requestDestroyed(sre);
274 } catch (Exception e) {
275 UndertowServletLogger.REQUEST_LOGGER.errorInvokingListener("requestDestroyed", listener.getListenerInfo().getListenerClass(), e);
276 }
277 }
278 }
279 }
280
281 public void servletRequestAttributeAdded(final HttpServletRequest request, final String name, final Object value) {
282 if(!started) {
283 return;
284 }
285 final ServletRequestAttributeEvent sre = new ServletRequestAttributeEvent(servletContext, request, name, value);
286 for (int i = 0; i < servletRequestAttributeListeners.length; ++i) {
287 this.<ServletRequestAttributeListener>get(servletRequestAttributeListeners[i]).attributeAdded(sre);
288 }
289 }
290
291 public void servletRequestAttributeRemoved(final HttpServletRequest request, final String name, final Object value) {
292 if(!started) {
293 return;
294 }
295 final ServletRequestAttributeEvent sre = new ServletRequestAttributeEvent(servletContext, request, name, value);
296 for (int i = 0; i < servletRequestAttributeListeners.length; ++i) {
297 this.<ServletRequestAttributeListener>get(servletRequestAttributeListeners[i]).attributeRemoved(sre);
298 }
299 }
300
301 public void servletRequestAttributeReplaced(final HttpServletRequest request, final String name, final Object value) {
302 if(!started) {
303 return;
304 }
305 final ServletRequestAttributeEvent sre = new ServletRequestAttributeEvent(servletContext, request, name, value);
306 for (int i = 0; i < servletRequestAttributeListeners.length; ++i) {
307 this.<ServletRequestAttributeListener>get(servletRequestAttributeListeners[i]).attributeReplaced(sre);
308 }
309 }
310
311 public void sessionCreated(final HttpSession session) {
312 if(!started) {
313 return;
314 }
315 final HttpSessionEvent sre = new HttpSessionEvent(session);
316 for (int i = 0; i < httpSessionListeners.length; ++i) {
317 this.<HttpSessionListener>get(httpSessionListeners[i]).sessionCreated(sre);
318 }
319 }
320
321 public void sessionDestroyed(final HttpSession session) {
322 if(!started) {
323 return;
324 }
325 final HttpSessionEvent sre = new HttpSessionEvent(session);
326 for (int i = httpSessionListeners.length - 1; i >= 0; --i) {
327 ManagedListener listener = httpSessionListeners[i];
328 this.<HttpSessionListener>get(listener).sessionDestroyed(sre);
329 }
330 }
331
332 public void httpSessionAttributeAdded(final HttpSession session, final String name, final Object value) {
333 if(!started) {
334 return;
335 }
336 final HttpSessionBindingEvent sre = new HttpSessionBindingEvent(session, name, value);
337 for (int i = 0; i < httpSessionAttributeListeners.length; ++i) {
338 this.<HttpSessionAttributeListener>get(httpSessionAttributeListeners[i]).attributeAdded(sre);
339 }
340 }
341
342 public void httpSessionAttributeRemoved(final HttpSession session, final String name, final Object value) {
343 if(!started) {
344 return;
345 }
346 final HttpSessionBindingEvent sre = new HttpSessionBindingEvent(session, name, value);
347 for (int i = 0; i < httpSessionAttributeListeners.length; ++i) {
348 this.<HttpSessionAttributeListener>get(httpSessionAttributeListeners[i]).attributeRemoved(sre);
349 }
350 }
351
352 public void httpSessionAttributeReplaced(final HttpSession session, final String name, final Object value) {
353 if(!started) {
354 return;
355 }
356 final HttpSessionBindingEvent sre = new HttpSessionBindingEvent(session, name, value);
357 for (int i = 0; i < httpSessionAttributeListeners.length; ++i) {
358 this.<HttpSessionAttributeListener>get(httpSessionAttributeListeners[i]).attributeReplaced(sre);
359 }
360 }
361
362 public void httpSessionIdChanged(final HttpSession session, final String oldSessionId) {
363 if(!started) {
364 return;
365 }
366 final HttpSessionEvent sre = new HttpSessionEvent(session);
367 for (int i = 0; i < httpSessionIdListeners.length; ++i) {
368 this.<HttpSessionIdListener>get(httpSessionIdListeners[i]).sessionIdChanged(sre, oldSessionId);
369 }
370 }
371
372 private <T> T get(final ManagedListener listener) {
373 return (T) listener.instance();
374 }
375
376
379 public static ListenerState listenerState() {
380 return IN_PROGRAMATIC_SC_LISTENER_INVOCATION.get();
381 }
382
383
387 public static boolean isListenerClass(final Class<?> clazz) {
388 for (Class c : LISTENER_CLASSES) {
389 if (c.isAssignableFrom(clazz)) {
390 return true;
391 }
392 }
393 return false;
394 }
395
396 public enum ListenerState {
397 NO_LISTENER,
398 DECLARED_LISTENER,
399 PROGRAMATIC_LISTENER,
400 }
401
402 }
403