View Javadoc

1   package com.atlassian.plugin.servlet.filter;
2   
3   import com.atlassian.plugin.Plugin;
4   import com.atlassian.plugin.PluginArtifact;
5   import com.atlassian.plugin.classloader.PluginClassLoader;
6   import com.atlassian.plugin.impl.DefaultDynamicPlugin;
7   import com.atlassian.plugin.servlet.descriptors.ServletFilterModuleDescriptor;
8   import com.atlassian.plugin.servlet.descriptors.ServletFilterModuleDescriptorBuilder;
9   import com.atlassian.plugin.servlet.filter.FilterTestUtils.FilterAdapter;
10  import static com.atlassian.plugin.servlet.filter.FilterTestUtils.emptyChain;
11  import static com.atlassian.plugin.servlet.filter.FilterTestUtils.newList;
12  import com.atlassian.plugin.test.PluginJarBuilder;
13  import static com.atlassian.plugin.test.PluginTestUtils.getFileForResource;
14  import com.mockobjects.dynamic.Mock;
15  import junit.framework.TestCase;
16  
17  import javax.servlet.*;
18  import javax.servlet.http.HttpServletRequest;
19  import javax.servlet.http.HttpServletResponse;
20  import java.io.File;
21  import java.io.IOException;
22  
23  import static org.mockito.Mockito.mock;
24  
25  public class TestDelegatingPluginFilter extends TestCase
26  {
27      public void testPluginClassLoaderIsThreadContextClassLoaderWhenFiltering() throws Exception
28      {
29          Mock mockRequest = new Mock(HttpServletRequest.class);
30          mockRequest.expectAndReturn("getPathInfo", "/servlet");
31  
32          Mock mockResponse = new Mock(HttpServletResponse.class);
33  
34          createClassLoaderCheckingFilter("filter").doFilter((HttpServletRequest) mockRequest.proxy(), (HttpServletResponse) mockResponse.proxy(), emptyChain);
35      }
36  
37      public void testClassLoaderResetDuringFilterChainExecution() throws Exception
38      {
39          Mock mockRequest = new Mock(HttpServletRequest.class);
40          mockRequest.expectAndReturn("getPathInfo", "/servlet");
41  
42          Mock mockResponse = new Mock(HttpServletResponse.class);
43  
44          final ClassLoader cl = Thread.currentThread().getContextClassLoader();
45          FilterChain chain = new FilterChain()
46          {
47              public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse) throws IOException, ServletException
48              {
49                  assertEquals(cl, Thread.currentThread().getContextClassLoader());
50              }
51          };
52          createClassLoaderCheckingFilter("filter").doFilter((HttpServletRequest) mockRequest.proxy(), (HttpServletResponse) mockResponse.proxy(), chain);
53      }
54      
55      public void testPluginClassLoaderIsThreadContextLoaderWhenFiltersInChainAreFromDifferentPlugins() throws Exception
56      {
57          Mock mockRequest = new Mock(HttpServletRequest.class);
58          mockRequest.matchAndReturn("getPathInfo", "/servlet");
59          Mock mockResponse = new Mock(HttpServletResponse.class);
60  
61          Iterable<Filter> filters = newList(
62              createClassLoaderCheckingFilter("filter-1"), 
63              createClassLoaderCheckingFilter("filter-2"), 
64              createClassLoaderCheckingFilter("filter-3")
65          );
66          FilterChain chain = new IteratingFilterChain(filters.iterator(), emptyChain);
67          chain.doFilter((HttpServletRequest) mockRequest.proxy(), (HttpServletResponse) mockResponse.proxy());
68      }
69      
70      public void testPluginClassLoaderIsRestoredProperlyWhenAnExceptionIsThrownFromFilter() throws Exception
71      {
72          Mock mockRequest = new Mock(HttpServletRequest.class);
73          mockRequest.matchAndReturn("getPathInfo", "/servlet");
74          Mock mockResponse = new Mock(HttpServletResponse.class);
75  
76          Iterable<Filter> filters = newList(
77              createClassLoaderCheckingFilter("filter-1"), 
78              createClassLoaderCheckingFilter("filter-2"),
79              createExceptionThrowingFilter("exception-filter"),
80              createClassLoaderCheckingFilter("filter-3")
81          );
82          FilterChain chain = new IteratingFilterChain(filters.iterator(), new FilterChain()
83          {
84              public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException
85              {
86                  fail("Exception should be thrown before reaching here.");
87              }
88          });
89          try
90          {
91              chain.doFilter((HttpServletRequest) mockRequest.proxy(), (HttpServletResponse) mockResponse.proxy());
92              fail("Exception should have been thrown");
93          }
94          catch (ServletException e)
95          {
96              // yay
97          }
98      }
99  
100     private Filter createClassLoaderCheckingFilter(final String name) throws Exception
101     {
102         File pluginFile = new PluginJarBuilder()
103                 .addFormattedJava("my.SimpleFilter",
104                         "package my;" +
105                         "import java.io.IOException;" +
106                         "import javax.servlet.Filter;" +
107                         "import javax.servlet.FilterChain;" +
108                         "import javax.servlet.FilterConfig;" +
109                         "import javax.servlet.ServletException;" +
110                         "import javax.servlet.ServletRequest;" +
111                         "import javax.servlet.ServletResponse;" +
112                         "" +
113                         "public class SimpleFilter implements Filter" +
114                         "{" +
115                         "    String name;" +
116                         "    public void init(FilterConfig filterConfig) throws ServletException" +
117                         "    {" +
118                         "        name = filterConfig.getInitParameter('name');" +
119                         "    }" +
120                         "" +
121                         "    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException" +
122                         "    {" +
123                         "        response.getWriter().write('entered: ' + name + '\');" +
124                         "        chain.doFilter(request, response);" +
125                         "        response.getWriter().write('exiting: ' + name + '\');" +
126                         "    }" +
127                         "    public void destroy() {}" +
128                         "}")
129                 .addFile("atlassian-plugin.xml", getFileForResource("com/atlassian/plugin/servlet/filter/atlassian-plugin-filter.xml"))
130                 .build();
131         final PluginClassLoader loader = new PluginClassLoader(pluginFile);
132         Plugin plugin = new DefaultDynamicPlugin((PluginArtifact) new Mock(PluginArtifact.class).proxy(), loader);
133         FilterAdapter testFilter = new FilterAdapter()
134         {
135             @Override
136             public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
137             {
138                 assertSame(name + " loader should be the thread context ClassLoader when entering", loader, Thread.currentThread().getContextClassLoader());
139                 chain.doFilter(request, response);
140                 assertSame(name + " loader should be the thread context ClassLoader when exiting", loader, Thread.currentThread().getContextClassLoader());
141             }
142         };
143 
144         ServletFilterModuleDescriptor filterDescriptor = new ServletFilterModuleDescriptorBuilder()
145             .with(testFilter)
146             .with(plugin)
147             .build();
148         
149         final Filter delegatingFilter = new DelegatingPluginFilter(filterDescriptor);
150         return delegatingFilter;
151     }
152     
153     private Filter createExceptionThrowingFilter(final String name)
154     {
155         return new FilterAdapter()
156         {
157             @Override
158             public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
159             {
160                 throw new ServletException(name);
161             }
162         };
163     }
164 }