View Javadoc

1   package com.atlassian.johnson.plugin.servlet.filter;
2   
3   import com.atlassian.johnson.Johnson;
4   import com.atlassian.johnson.JohnsonEventContainer;
5   import com.atlassian.plugin.servlet.filter.ServletFilterModuleContainerFilter;
6   import org.slf4j.Logger;
7   import org.slf4j.LoggerFactory;
8   
9   import javax.servlet.FilterChain;
10  import javax.servlet.ServletException;
11  import javax.servlet.ServletRequest;
12  import javax.servlet.ServletResponse;
13  import java.io.IOException;
14  
15  /**
16   * Extends the plugin framework's {@code ServletFilterModuleContainerFilter} to bypass servlet-provided filters when
17   * Johnson {@link com.atlassian.johnson.event.Event events} are present.
18   * <p>
19   * When the system is Johnsoned, the exact set of resources that are available is unknown. In some cases, that can
20   * cause plugin-provided filters which attempt to access those resources to fail in an unexpected ways. That, in turn
21   * can block access to Johnson's error page, or even hang request threads. Replacing the standard filter with this
22   * Johnson-aware version ensures servlet-provided filters are automatically bypassed while Johnson events are present.
23   *
24   * @since 3.0
25   */
26  public class JohnsonServletFilterModuleContainerFilter extends ServletFilterModuleContainerFilter {
27  
28      private static final Logger log = LoggerFactory.getLogger(JohnsonServletFilterModuleContainerFilter.class);
29  
30      /**
31       * Checks whether plugin-provided filters should be {@link #bypassFilters() bypassed} and, if so, directly
32       * invokes the {@code FilterChain}; otherwise, processes {@code super.doFilter} normally.
33       *
34       * @param request  the request
35       * @param response the response
36       * @param chain    the remaining filter chain
37       * @throws IOException      if thrown by the base class, or the {@code FilterChain}
38       * @throws ServletException if thrown by the base class, or the {@code FilterChain}
39       */
40      @Override
41      public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
42              throws IOException, ServletException {
43          if (bypassFilters()) {
44              //If there are Johnson events, bypass plugin filters. This ensures those filters don't attempt
45              //to interact with system resources which are not ready
46              log.debug("{}: Bypassing plugin-provided filters; the system is locked", getFilterLocation());
47              chain.doFilter(request, response);
48          } else {
49              //Otherwise, if there are no events, dispatch through servlet filters if they are available
50              super.doFilter(request, response, chain);
51          }
52      }
53  
54      /**
55       * Determines whether plugin-provided filters should be bypassed. The default implementation bypasses plugin-
56       * provided filters whenever there are events in the {@link #getEventContainer() container}.
57       * <p>
58       * Applications can override this method in subclasses to apply a more specific set of restrictions. For example,
59       * they could choose to allow plugin-provided filters to be applied in specific Johnson states, or based on other
60       * knowledge of the application as a whole.
61       *
62       * @return {@code true} if plugin-provided filters should be bypassed; otherwise, {@code false} to apply
63       *         plugin-provided filters normally
64       */
65      protected boolean bypassFilters() {
66          return getEventContainer().hasEvents();
67      }
68  
69      /**
70       * Retrieves the {@link JohnsonEventContainer} using the {@code FilterConfig}'s {@code ServletContext}.
71       *
72       * @return the {@link JohnsonEventContainer}
73       */
74      protected JohnsonEventContainer getEventContainer() {
75          return Johnson.getEventContainer(getFilterConfig().getServletContext());
76      }
77  }