View Javadoc

1   package com.atlassian.johnson.spring.web.context.support;
2   
3   import com.atlassian.johnson.Johnson;
4   import com.atlassian.johnson.config.JohnsonConfig;
5   import com.atlassian.johnson.event.Event;
6   import com.atlassian.johnson.spring.web.context.JohnsonContextLoaderListener;
7   import org.slf4j.Logger;
8   import org.slf4j.LoggerFactory;
9   import org.springframework.web.context.support.HttpRequestHandlerServlet;
10  
11  import javax.annotation.Nonnull;
12  import javax.servlet.ServletContext;
13  import javax.servlet.ServletException;
14  import javax.servlet.http.HttpServletRequest;
15  import javax.servlet.http.HttpServletResponse;
16  import java.io.IOException;
17  
18  /**
19   * @since 2.1
20   */
21  public class JohnsonHttpRequestHandlerServlet extends HttpRequestHandlerServlet {
22  
23      private static final Logger LOG = LoggerFactory.getLogger(JohnsonHttpRequestHandlerServlet.class);
24  
25      private final Object lock = new Object();
26  
27      private volatile boolean uninitialised = true;
28  
29      @Override
30      public void init() throws ServletException {
31          //During startup, we'd like to initialise if possible because doing so here doesn't require locking. However,
32          //if the WebApplicationContext was bypassed, attempting to initialise here will fail and may make the entire
33          //server inaccessible. That would prevent accessing the Johnson page, so if the WebApplicationContext is not
34          //available we bypass initialisation here.
35          maybeInit();
36      }
37  
38      protected void sendRedirect(@Nonnull HttpServletResponse response) throws IOException {
39          ServletContext servletContext = getServletContext();
40          JohnsonConfig config = Johnson.getConfig(servletContext);
41  
42          LOG.warn("HttpRequestHandlerServlet [{}] cannot be initialised to service an incoming " +
43                  "request; redirecting to {}", getServletName(), config.getErrorPath());
44          response.sendRedirect(servletContext.getContextPath() + config.getErrorPath());
45      }
46  
47      @Override
48      protected void service(@Nonnull HttpServletRequest request, @Nonnull HttpServletResponse response)
49              throws ServletException, IOException {
50          //When a request comes in, we're required to be initialised. If we're not, the only possible reason is that
51          //the application is Johnsoned. That suggests we will not be able to initialise here, but we still try, on
52          //the assumption that this URL was allowed through the Johnson filter and may, therefore, work. If so, the
53          //request will be processed normally.
54          if (uninitialised) {
55              synchronized (lock) {
56                  if (uninitialised) {
57                      if (!maybeInit()) {
58                          //If we can't initialise at this point, redirect to the Johnson error page. The filter should
59                          //not have allowed access to this URL.
60                          sendRedirect(response);
61  
62                          return;
63                      }
64                  }
65              }
66          }
67  
68          super.service(request, response);
69      }
70  
71      private boolean maybeInit() throws ServletException {
72          ServletContext servletContext = getServletContext();
73  
74          Object attribute = servletContext.getAttribute(JohnsonContextLoaderListener.ATTR_BYPASSED);
75          //First, check to see if the WebApplicationContext was bypassed. If it was, it's possible, based on
76          //configuration, that no event was added. However, we must bypass handler initialisation as well,
77          //because no parent context will be available.
78          if (Boolean.TRUE == attribute) //Fully bypassed, without even trying to start
79          {
80              LOG.error("Bypassing HttpRequestHandlerServlet [{}] initialisation; Spring initialisation was bypassed",
81                      getServletName());
82              return false;
83          }
84          //If WebApplicationContext initialisation wasn't bypassed, check to see if it failed. Handler initialisation
85          //is guaranteed to fail if the primary WebApplicationContext failed, so we'll want to bypass it.
86          if (attribute instanceof Event) {
87              Event event = (Event) attribute;
88  
89              LOG.error("Bypassing HttpRequestHandlerServlet [{}] initialisation; Spring initialisation failed: {}",
90                      getServletName(), event.getDesc());
91              return false;
92          }
93  
94          //If we make it here, the Spring WebApplicationContext should have started successfully. That means it's safe
95          //to try and start this handler.
96          try {
97              super.init();
98  
99              //No longer uninitialised, so future calls through this servlet should be serviced normally. Setting this
100             //optimises the locking out of the service(...) method.
101             uninitialised = false;
102         } catch (Exception e) {
103             LOG.error("HttpRequestHandlerServlet [" + getServletName() + "] could not be started", e);
104 
105             return false;
106         }
107 
108         return true;
109     }
110 }