View Javadoc

1   package com.atlassian.johnson.spring.web.servlet.support;
2   
3   import com.atlassian.johnson.context.JohnsonContextListener;
4   import com.atlassian.johnson.spring.web.context.JohnsonContextLoaderListener;
5   import com.atlassian.johnson.spring.web.servlet.JohnsonDispatcherServlet;
6   import org.springframework.util.Assert;
7   import org.springframework.util.ObjectUtils;
8   import org.springframework.web.context.ContextLoaderListener;
9   import org.springframework.web.context.WebApplicationContext;
10  import org.springframework.web.servlet.DispatcherServlet;
11  import org.springframework.web.servlet.support.AbstractDispatcherServletInitializer;
12  
13  import javax.servlet.Filter;
14  import javax.servlet.ServletContext;
15  import javax.servlet.ServletException;
16  import javax.servlet.ServletRegistration;
17  
18  /**
19   * Extends Spring's {@code AbstractDispatcherServletInitializer} to use Johnson-aware components.
20   * <ul>
21   * <li>A {@link JohnsonContextListener} will be registered <i>before</i> any other listeners that are registered
22   * by this initializer</li>
23   * <li>A {@link JohnsonContextLoaderListener} will be used to initialize the {@link #createRootApplicationContext()
24   * root ApplicationContext}, if one is created</li>
25   * <li>A {@link JohnsonDispatcherServlet} will be used to initialize the {@link #createServletApplicationContext()
26   * servlet ApplicationContext}</li>
27   * </ul>
28   * <p>
29   * In addition to using Johnson-aware components by default, this base class allows derived initializers to override
30   * {@link #createContextLoaderListener(WebApplicationContext) the ContextLoaderListener} and
31   * {@link #createDispatcherServlet(WebApplicationContext) DispatcherServlet} types used. This is intended to allow
32   * for application-specific handling on top of the Johnson-aware handling.
33   *
34   * @since 3.0
35   */
36  public abstract class AbstractJohnsonDispatcherServletInitializer extends AbstractDispatcherServletInitializer {
37  
38      /**
39       * Creates a {@link JohnsonContextLoaderListener} which will initialize and terminate the provided
40       * {@code WebApplicationContext}. This method is provided as a convenience for derived classes to
41       * simplify replacing the listener used.
42       *
43       * @param context the {@code WebApplicationContext} to be initialized by the created listener
44       * @return the listener to register with the {@code ServletContext}
45       */
46      protected ContextLoaderListener createContextLoaderListener(WebApplicationContext context) {
47          return new JohnsonContextLoaderListener(context);
48      }
49  
50      /**
51       * Creates a {@link JohnsonDispatcherServlet}, which will initialize the SpringMVC context in a Johnson-aware
52       * away. If SpringMVC initialization fails, the application will be locked.
53       *
54       * @param context the {@code WebApplicationContext} to be initialized by the created dispatcher
55       * @return the servlet to register with the {@code ServletContext}
56       */
57      protected DispatcherServlet createDispatcherServlet(WebApplicationContext context) {
58          return new JohnsonDispatcherServlet(context);
59      }
60  
61      /**
62       * {@link #registerJohnsonContextListener(ServletContext) Registers a} {@link JohnsonContextListener} and then
63       * delegates to the superclass's {@code onStartup(ServletContext)} implementation.
64       *
65       * @param servletContext the {@code ServletContext} to initialize
66       * @throws ServletException potentially thrown by the superclass {@code onStartup(ServletContext)} implementation
67       */
68      @Override
69      public void onStartup(ServletContext servletContext) throws ServletException {
70          registerJohnsonContextListener(servletContext);
71  
72          super.onStartup(servletContext);
73      }
74  
75      /**
76       * Overrides {@code AbstractContextLoaderListener}'s {@code registerContextLoaderListener} to register a
77       * {@link #createContextLoaderListener(WebApplicationContext) JohnsonContextLoaderListener} instead of the
78       * standard Spring {@code ContextLoaderListener}.
79       *
80       * @param servletContext the {@code ServletContext} to register the {@link JohnsonContextLoaderListener} in
81       */
82      @Override
83      protected void registerContextLoaderListener(ServletContext servletContext) {
84          WebApplicationContext context = createRootApplicationContext();
85          if (context == null) {
86              logger.debug("No ContextLoaderListener registered, as createRootApplicationContext() did not return an application context");
87          } else {
88              servletContext.addListener(createContextLoaderListener(context));
89          }
90      }
91  
92      /**
93       * Overrides {@code AbstractDispatcherServletInitializer}'s {@code registerDispatcherServlet(ServletContext)} to
94       * register a {@link #createDispatcherServlet(WebApplicationContext) JohnsonDispatcherServlet} instead of the
95       * standard Spring {@code DispatcherServlet}.
96       *
97       * @param servletContext the {@code ServletContext} to register the {@link JohnsonDispatcherServlet} in
98       */
99      @Override
100     protected void registerDispatcherServlet(ServletContext servletContext) {
101         String servletName = getServletName();
102         Assert.hasLength(servletName, "getServletName() may not return empty or null");
103 
104         WebApplicationContext servletAppContext = createServletApplicationContext();
105         Assert.notNull(servletAppContext,
106                 "createServletApplicationContext() did not return an application context for servlet ["
107                         + servletName + "]"
108         );
109 
110         ServletRegistration.Dynamic registration =
111                 servletContext.addServlet(servletName, createDispatcherServlet(servletAppContext));
112         Assert.notNull(registration,
113                 "Failed to register servlet with name '" + servletName +
114                         "'. Check if there is another servlet registered under the same name."
115         );
116 
117         registration.setAsyncSupported(isAsyncSupported());
118         registration.setLoadOnStartup(1);
119         registration.addMapping(getServletMappings());
120 
121         Filter[] filters = getServletFilters();
122         if (!ObjectUtils.isEmpty(filters)) {
123             for (Filter filter : filters) {
124                 registerServletFilter(servletContext, filter);
125             }
126         }
127 
128         customizeRegistration(registration);
129     }
130 
131     /**
132      * Registers an {@link JohnsonContextListener} in in the provided {@code ServletContext}. This listener ensures
133      * Johnson is initialized and terminated with the application.
134      * <p>
135      * Note: Even if this method is called multiple times, with its default implementation the listener will only be
136      * added <i>once</i>.
137      *
138      * @param servletContext the {@code ServletContext} to register the {@link JohnsonContextListener} in
139      * @see JohnsonContextListener#register(ServletContext)
140      */
141     protected void registerJohnsonContextListener(ServletContext servletContext) {
142         JohnsonContextListener.register(servletContext);
143     }
144 }