View Javadoc

1   package com.atlassian.plugin.servlet.filter;
2   
3   import java.io.IOException;
4   
5   import javax.servlet.Filter;
6   import javax.servlet.FilterChain;
7   import javax.servlet.FilterConfig;
8   import javax.servlet.ServletException;
9   import javax.servlet.ServletRequest;
10  import javax.servlet.ServletResponse;
11  import javax.servlet.http.HttpServletRequest;
12  
13  import com.atlassian.plugin.servlet.PluginHttpRequestWrapper;
14  import com.atlassian.plugin.servlet.descriptors.ServletFilterModuleDescriptor;
15  import com.atlassian.plugin.servlet.util.ClassLoaderStack;
16  
17  /**
18   * We wrap the plugins filter so that we can set some things up before the plugins filter is called. Currently we do 
19   * the following:
20   *      <ul>
21   *        <li>set the Threads classloader to the plugins classloader)</li>
22   *        <li>wrap the request so that path info is right for the filters</li>
23   *      </ul>
24   *      
25   * @since 2.1.0
26   */
27  public class DelegatingPluginFilter implements Filter
28  {
29      private final ServletFilterModuleDescriptor descriptor;
30      private final Filter filter;
31      
32      public DelegatingPluginFilter(ServletFilterModuleDescriptor descriptor)
33      {
34          this.descriptor = descriptor;
35          this.filter = descriptor.getModule();
36      }
37  
38      public void init(FilterConfig filterConfig) throws ServletException
39      {
40          ClassLoaderStack.push(descriptor.getPlugin().getClassLoader());
41          try
42          {
43              filter.init(filterConfig);
44          }
45          finally
46          {
47              ClassLoaderStack.pop();
48          }
49      }
50  
51      public void doFilter(ServletRequest request, ServletResponse response, final FilterChain chain)
52          throws IOException, ServletException
53      {
54          // Cache the class loader in case the chain below disabled the plugin making getClassLoader() inaccessible. This
55          // is a bit dodgy, but it's a concession to the fact that web actions result in plugin disablement. The post
56          // chain push only lasts until we exit back the outer push here.
57          final ClassLoader pluginClassLoader = descriptor.getPlugin().getClassLoader();
58          ClassLoaderStack.push(pluginClassLoader);
59          try
60          {
61              // Reset the classloader during chain execution to prevent plugin's classloader being used for the duration
62              // of the request
63              FilterChain resetContextClassLoaderChain = new FilterChain()
64              {
65                  public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse) throws IOException, ServletException
66                  {
67                      ClassLoaderStack.pop();
68                      try
69                      {
70                          chain.doFilter(servletRequest, servletResponse);
71                      }
72                      finally
73                      {
74                          ClassLoaderStack.push(pluginClassLoader);
75                      }
76                  }
77              };
78              filter.doFilter(new PluginHttpRequestWrapper((HttpServletRequest) request, descriptor), response, resetContextClassLoaderChain);
79          }
80          finally
81          {
82              ClassLoaderStack.pop();
83          }
84      }
85      
86      public void destroy()
87      {
88          ClassLoaderStack.push(descriptor.getPlugin().getClassLoader());
89          try
90          {
91              filter.destroy();
92          }
93          finally
94          {
95              ClassLoaderStack.pop();
96          }
97      }
98  
99      public Filter getDelegatingFilter()
100     {
101         return filter;
102     }
103 }