/** * Wrapper around {@link #doFilterInternal(HttpServletRequest, HttpServletResponse, FilterChain)} to make sure this * filter's logic is only executed once per request. */ @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException { if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) { throw new ServletException(this.getClass().getName() + " only supports HTTP requests"); } HttpServletRequest httpRequest = (HttpServletRequest) request; HttpServletResponse httpResponse = (HttpServletResponse) response; boolean filterHasAlreadyExecuted = request.getAttribute(FILTER_HAS_ALREADY_EXECUTED_ATTRIBUTE) != null; if (filterHasAlreadyExecuted || skipDispatch(httpRequest)) { // Already executed or we're supposed to skip, so continue the filter chain without doing the // distributed tracing work. filterChain.doFilter(request, response); } else { // Time to execute the distributed tracing logic. request.setAttribute(FILTER_HAS_ALREADY_EXECUTED_ATTRIBUTE, Boolean.TRUE); doFilterInternal(httpRequest, httpResponse, filterChain); } }
@Test public void skipDispatch_should_return_false() { // given: filter RequestTracingFilter filter = getBasicFilter(); // when: skipDispatchIsCalled boolean result = filter.skipDispatch(requestMock); // then: the result should be false assertThat(result).isFalse(); }
@Test public void doFilter_should_not_call_doFilterInternal_if_not_already_filtered_but_skipDispatch_returns_true( ) throws IOException, ServletException { // given: request that returns null for already-filtered attribute but filter that returns true for skipDispatch RequestTracingFilter spyFilter = spy(getBasicFilter()); doReturn(true).when(spyFilter).skipDispatch(any(HttpServletRequest.class)); given(requestMock.getAttribute(RequestTracingFilter.FILTER_HAS_ALREADY_EXECUTED_ATTRIBUTE)).willReturn(null); // when: doFilter() is called spyFilter.doFilter(requestMock, responseMock, filterChainMock); // then: doFilterInternal should not be called verify(spyFilter, times(0)).doFilterInternal(requestMock, responseMock, filterChainMock); verify(spyFilter).skipDispatch(requestMock); }