1 package com.atlassian.johnson.context;
2
3 import com.atlassian.johnson.Johnson;
4
5 import javax.annotation.Nonnull;
6 import javax.servlet.ServletContext;
7 import javax.servlet.ServletContextEvent;
8 import javax.servlet.ServletContextListener;
9
10 /**
11 * Initialises and terminates {@link Johnson} with the servlet container.
12 * <p>
13 * In web environments, this is the preferred mechanism for managing Johnson's lifecycle, allowing it to be initialised
14 * and terminated in a thread-safe context. This listener should be registered before any others except, if applicable,
15 * those that setup logging.
16 * <p>
17 * To use this listener, add the following to web.xml:
18 * <pre>
19 * <code><listener>
20 * <listener-class>com.atlassian.johnson.context.JohnsonContextListener</listener-class>
21 * </listener>
22 * </code>
23 * </pre>
24 * Alternatively, if the application is deployed in a Servlet 3 container such as Tomcat 7, this listener can be
25 * registered in a {@code ServletContainerInitializer} using {@code ServletContext.addListener}.
26 *
27 * @since 2.0
28 */
29 public class JohnsonContextListener implements ServletContextListener {
30
31 /**
32 * When a {@code JohnsonContextListener} {@link #register(ServletContext) is registered} with a
33 * {@code ServletContext}, this attribute will be used to mark its registration so that multiple
34 * listeners will not be registered.
35 *
36 * @since 3.0
37 */
38 public static final String ATTR_REGISTERED = JohnsonContextListener.class.getName() + ":Registered";
39
40 /**
41 * Registers a {@code JohnsonContextListener} with the provided {@code ServletContext} if such a listener has not
42 * already been registered.
43 * <p>
44 * This method is for use as part of Servlet 3-style {@code ServletContainerInitializer} initialization. Listeners
45 * cannot be added to {@code ServletContext} instances after they have already been initialized.
46 *
47 * @param context the {@code ServletContext} to register a {@link JohnsonContextListener} with
48 * @throws IllegalArgumentException if the provided {@link ServletContext} was not passed to
49 * {@link javax.servlet.ServletContainerInitializer#onStartup(java.util.Set, ServletContext)}
50 * @throws IllegalStateException if the {@link ServletContext} has already been initialized
51 * @throws UnsupportedOperationException if this {@link ServletContext} was passed to the
52 * {@link ServletContextListener#contextInitialized(ServletContextEvent)} method of a
53 * {@link ServletContextListener} that was not either declared in {@code web.xml} or
54 * {@code web-fragment.xml} or annotated with {@code @WebListener}
55 * @since 3.0
56 */
57 public static void register(@Nonnull ServletContext context) {
58 if (context.getAttribute(ATTR_REGISTERED) == null) {
59 context.addListener(new JohnsonContextListener());
60 context.setAttribute(ATTR_REGISTERED, Boolean.TRUE);
61 }
62 }
63
64 /**
65 * Terminates {@link Johnson}.
66 *
67 * @param event the context event
68 * @see Johnson#terminate(javax.servlet.ServletContext)
69 */
70 public void contextDestroyed(@Nonnull ServletContextEvent event) {
71 Johnson.terminate(event.getServletContext());
72 }
73
74 /**
75 * Initialises {@link Johnson}.
76 *
77 * @param event the context event
78 * @see Johnson#initialize(javax.servlet.ServletContext)
79 */
80 public void contextInitialized(@Nonnull ServletContextEvent event) {
81 Johnson.initialize(event.getServletContext());
82 }
83 }