### Question:
IteratingFilterChain implements FilterChain { public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException { if (iterator.hasNext()) { Filter filter = iterator.next(); filter.doFilter(request, response, this); } else { chain.doFilter(request, response); } } IteratingFilterChain(Iterator<Filter> iterator, FilterChain chain); void doFilter(ServletRequest request, ServletResponse response);  }### Answer:
@Test public void testExceptionFiltersUpWhenFilterThrowsException() throws IOException, ServletException { final List<Integer> filterCallOrder = new LinkedList<Integer>(); List<Filter> filters = new ArrayList<Filter>(); for (int i = 0; i < 2; i++) { filters.add(new SoundOffFilter(filterCallOrder, i)); } filters.add(new FilterAdapter() { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { throw new ServletException(); } }); for (int i = 3; i < 5; i++) { filters.add(new SoundOffFilter(filterCallOrder, i)); } FilterChain chain = new IteratingFilterChain(filters.iterator(), singletonFilterChain(new SoundOffFilter(filterCallOrder, 100))); Mock mockRequest = new Mock(HttpServletRequest.class); mockRequest.expectAndReturn("getPathInfo", "some/path"); Mock mockResponse = new Mock(HttpServletResponse.class); try { chain.doFilter((HttpServletRequest) mockRequest.proxy(), (HttpServletResponse) mockResponse.proxy()); fail("ServletException should filter up"); } catch (ServletException e) { assertEquals(newList(0, 1), filterCallOrder); } }
@Test public void testFilterCanAbortChain() throws IOException, ServletException { final List<Integer> filterCallOrder = new LinkedList<Integer>(); List<Filter> filters = new ArrayList<Filter>(); for (int i = 0; i < 2; i++) { filters.add(new SoundOffFilter(filterCallOrder, i)); } filters.add(new FilterAdapter() { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { filterCallOrder.add(50); } }); for (int i = 3; i < 5; i++) { filters.add(new SoundOffFilter(filterCallOrder, i)); } FilterChain chain = new IteratingFilterChain(filters.iterator(), singletonFilterChain(new SoundOffFilter(filterCallOrder, 100))); Mock mockRequest = new Mock(HttpServletRequest.class); mockRequest.expectAndReturn("getPathInfo", "some/path"); Mock mockResponse = new Mock(HttpServletResponse.class); chain.doFilter((HttpServletRequest) mockRequest.proxy(), (HttpServletResponse) mockResponse.proxy()); assertEquals(newList(0, 1, 50, 1, 0), filterCallOrder); }
@Test public void testFiltersCalledInProperOrder() throws IOException, ServletException { List<Integer> filterCallOrder = new LinkedList<Integer>(); List<Filter> filters = new ArrayList<Filter>(); for (int i = 0; i < 5; i++) { filters.add(new SoundOffFilter(filterCallOrder, i)); } FilterChain chain = new IteratingFilterChain(filters.iterator(), singletonFilterChain(new SoundOffFilter(filterCallOrder, 100))); Mock mockRequest = new Mock(HttpServletRequest.class); mockRequest.expectAndReturn("getPathInfo", "some/path"); Mock mockResponse = new Mock(HttpServletResponse.class); chain.doFilter((HttpServletRequest) mockRequest.proxy(), (HttpServletResponse) mockResponse.proxy()); assertEquals(newList(0, 1, 2, 3, 4, 100, 100, 4, 3, 2, 1, 0), filterCallOrder); }