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
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 }