### Question:
DelegatingPluginFilter implements Filter { public void doFilter(ServletRequest request, ServletResponse response, final FilterChain chain) throws IOException, ServletException { ClassLoaderStack.push(descriptor.getPlugin().getClassLoader()); try { FilterChain resetContextClassLoaderChain = new FilterChain() { public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse) throws IOException, ServletException { ClassLoaderStack.pop(); try { chain.doFilter(servletRequest, servletResponse); } finally { ClassLoaderStack.push(descriptor.getPlugin().getClassLoader()); } } }; filter.doFilter(new PluginHttpRequestWrapper((HttpServletRequest) request, descriptor), response, resetContextClassLoaderChain); } finally { ClassLoaderStack.pop(); } } DelegatingPluginFilter(ServletFilterModuleDescriptor descriptor); void init(FilterConfig filterConfig); void doFilter(ServletRequest request, ServletResponse response, final FilterChain chain); void destroy(); Filter getDelegatingFilter();  }### Answer:
@Test public void testClassLoaderResetDuringFilterChainExecution() throws Exception { Mock mockRequest = new Mock(HttpServletRequest.class); mockRequest.expectAndReturn("getPathInfo", "/servlet"); Mock mockResponse = new Mock(HttpServletResponse.class); final ClassLoader cl = Thread.currentThread().getContextClassLoader(); FilterChain chain = new FilterChain() { public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse) throws IOException, ServletException { assertEquals(cl, Thread.currentThread().getContextClassLoader()); } }; createClassLoaderCheckingFilter("filter").doFilter((HttpServletRequest) mockRequest.proxy(), (HttpServletResponse) mockResponse.proxy(), chain); }
@Test public void testPluginClassLoaderIsRestoredProperlyWhenAnExceptionIsThrownFromFilter() throws Exception { Mock mockRequest = new Mock(HttpServletRequest.class); mockRequest.matchAndReturn("getPathInfo", "/servlet"); Mock mockResponse = new Mock(HttpServletResponse.class); Iterable<Filter> filters = newList( createClassLoaderCheckingFilter("filter-1"), createClassLoaderCheckingFilter("filter-2"), createExceptionThrowingFilter("exception-filter"), createClassLoaderCheckingFilter("filter-3") ); FilterChain chain = new IteratingFilterChain(filters.iterator(), new FilterChain() { public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException { fail("Exception should be thrown before reaching here."); } }); try { chain.doFilter((HttpServletRequest) mockRequest.proxy(), (HttpServletResponse) mockResponse.proxy()); fail("Exception should have been thrown"); } catch (ServletException ignored) { } }
@Test public void testPluginClassLoaderIsThreadContextClassLoaderWhenFiltering() throws Exception { Mock mockRequest = new Mock(HttpServletRequest.class); mockRequest.expectAndReturn("getPathInfo", "/servlet"); Mock mockResponse = new Mock(HttpServletResponse.class); createClassLoaderCheckingFilter("filter").doFilter((HttpServletRequest) mockRequest.proxy(), (HttpServletResponse) mockResponse.proxy(), emptyChain); }
@Test public void testPluginClassLoaderIsThreadContextLoaderWhenFiltersInChainAreFromDifferentPlugins() throws Exception { Mock mockRequest = new Mock(HttpServletRequest.class); mockRequest.matchAndReturn("getPathInfo", "/servlet"); Mock mockResponse = new Mock(HttpServletResponse.class); Iterable<Filter> filters = newList( createClassLoaderCheckingFilter("filter-1"), createClassLoaderCheckingFilter("filter-2"), createClassLoaderCheckingFilter("filter-3") ); FilterChain chain = new IteratingFilterChain(filters.iterator(), emptyChain); chain.doFilter((HttpServletRequest) mockRequest.proxy(), (HttpServletResponse) mockResponse.proxy()); }