/** * Determines whether the current servlet container supports Servlet 3 async requests by using reflection to * inspect the given {@link ServletRequest} implementation class to see if it contains an async-related method * introduced with the Servlet 3 API, and attempts to use the given string to load the class for * {@code javax.servlet.AsyncListener}. If both of those checks pass without error then {@link Servlet3Runtime} * will be returned, otherwise a Servlet 2.x environment is assumed and {@link Servlet2Runtime} will be returned. * * @param servletRequestClass The {@link ServletRequest} implementation class to check. * @param asyncListenerClassname This should be "javax.servlet.AsyncListener" at runtime (use the {@link * #ASYNC_LISTENER_CLASSNAME} constant). It is passed in as an argument to facilitate testing scenarios. * @return true if the given {@link ServletRequest} implementation class supports the getAsyncContext() method * and the given {@code javax.servlet.AsyncListener} classname could be loaded, otherwise false. */ static ServletRuntime determineServletRuntime(Class<?> servletRequestClass, String asyncListenerClassname) { try { servletRequestClass.getMethod("getAsyncContext"); Class.forName(asyncListenerClassname); // No exceptions were thrown, so we're running in a Servlet 3+ environment. return new Servlet3Runtime(); } catch (Exception ex) { logger.warn( "Servlet 3 async requests are not supported on the current container. " + "RequestTracingFilter will default to blocking request behavior (Servlet 2.x). " + "Exception message indicating a Servlet 2.x environment: {}", ex.toString() ); return new Servlet2Runtime(); } }
@Test public void setupTracingCompletionWhenAsyncRequestCompletes_should_add_WingtipsRequestSpanCompletionAsyncListener( ) { // given AsyncContext asyncContextMock = mock(AsyncContext.class); doReturn(asyncContextMock).when(requestMock).getAsyncContext(); TracingState tracingStateMock = mock(TracingState.class); HttpTagAndSpanNamingStrategy<HttpServletRequest, HttpServletResponse> tagStrategyMock = mock(HttpTagAndSpanNamingStrategy.class); HttpTagAndSpanNamingAdapter<HttpServletRequest,HttpServletResponse> tagAdapterMock = mock(HttpTagAndSpanNamingAdapter.class); ArgumentCaptor<AsyncListener> listenerCaptor = ArgumentCaptor.forClass(AsyncListener.class); // when servlet3Runtime.setupTracingCompletionWhenAsyncRequestCompletes( requestMock, responseMock, tracingStateMock, tagStrategyMock, tagAdapterMock ); // then verify(asyncContextMock).addListener(listenerCaptor.capture(), eq(requestMock), eq(responseMock)); List<AsyncListener> addedListeners = listenerCaptor.getAllValues(); assertThat(addedListeners).hasSize(1); assertThat(addedListeners.get(0)).isInstanceOf(WingtipsRequestSpanCompletionAsyncListener.class); WingtipsRequestSpanCompletionAsyncListener listener = (WingtipsRequestSpanCompletionAsyncListener)addedListeners.get(0); assertThat(listener.originalRequestTracingState).isSameAs(tracingStateMock); assertThat(listener.tagAndNamingStrategy).isSameAs(tagStrategyMock); assertThat(listener.tagAndNamingAdapter).isSameAs(tagAdapterMock); }
@DataProvider(value = { "FORWARD | false", "INCLUDE | false", "REQUEST | false", "ASYNC | true", "ERROR | false" }, splitBy = "\\|") @Test public void servlet3_isAsyncDispatch_returns_result_based_on_request_dispatcher_type( DispatcherType dispatcherType, boolean expectedResult ) { // given doReturn(dispatcherType).when(requestMock).getDispatcherType(); // when boolean result = servlet3Runtime.isAsyncDispatch(requestMock); // then assertThat(result).isEqualTo(expectedResult); } }
@DataProvider(value = { "true", "false" }, splitBy = "\\|") @Test public void isAsyncRequest_should_return_the_value_of_request_isAsyncStarted(boolean requestIsAsyncStarted) { // given Servlet3Runtime implSpy = spy(servlet3Runtime); doReturn(requestIsAsyncStarted).when(requestMock).isAsyncStarted(); // when boolean result = implSpy.isAsyncRequest(requestMock); // then assertThat(result).isEqualTo(requestIsAsyncStarted); verify(requestMock).isAsyncStarted(); verify(implSpy).isAsyncRequest(requestMock); verifyNoMoreInteractions(implSpy); }
@Before public void beforeMethod() { servlet2Runtime = new Servlet2Runtime(); servlet3Runtime = new Servlet3Runtime(); requestMock = mock(HttpServletRequest.class); responseMock = mock(HttpServletResponse.class); }