All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.nike.wingtips.servlet.ServletRuntime Maven / Gradle / Ivy

package com.nike.wingtips.servlet;

import com.nike.wingtips.util.TracingState;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;

/**
 * A class for abstracting out bits of the Servlet API that are version-dependent, e.g. async request support
 * doesn't show up until Servlet 3.0 API. This abstraction allows us to have one servlet filter that works in
 * pre-Servlet-3 or post-Servlet-3 environments without receiving class-not-found or method-not-found exceptions.
 *
 * 

This class was derived from * * Brave's ServletRuntime, which was itself derived from OkHttp's {@code okhttp3.internal.platform.Platform}. * *

You should not need to worry about this class - it is an internal implementation detail for * {@link RequestTracingFilter}. * * @author Nic Munroe */ abstract class ServletRuntime { private static final Logger logger = LoggerFactory.getLogger(ServletRuntime.class); /** * The classname for {@code AsyncListener}. Pass this in to {@link #determineServletRuntime(Class, String)} along * with the servlet request class to determine which servlet runtime environment you're running in. */ static final String ASYNC_LISTENER_CLASSNAME = "javax.servlet.AsyncListener"; /** * @param request The request to inspect to see if it's async or not. * @return true if the given request represents an async request, false otherwise. */ abstract boolean isAsyncRequest(HttpServletRequest request); /** * This method should be overridden to do the right thing depending on the Servlet runtime environment - Servlet * 2.x environments should do nothing or throw an exception since they do not support async requests (and this * method should never be called since {@link #isAsyncRequest(HttpServletRequest)} should return false), but * Servlet 3+ environments should setup a listener that will complete the given {@link TracingState} when the given * async request finishes. The listener code would look something like: * *

     *      AsyncListener spanCompletingAsyncListener = ...;
     *      asyncRequest.getAsyncContext().addListener(spanCompletingAsyncListener);
     * 
* * @param asyncRequest The async servlet request (guaranteed to be async since this method will only be called when * {@link #isAsyncRequest(HttpServletRequest)} returns true). * @param originalRequestTracingState The {@link TracingState} that was generated when this request started, and * which should be completed when the given async servlet request finishes. */ abstract void setupTracingCompletionWhenAsyncRequestCompletes(HttpServletRequest asyncRequest, TracingState originalRequestTracingState); /** * The dispatcher type {@code javax.servlet.DispatcherType.ASYNC} introduced in Servlet 3.0 means a filter can be * invoked in more than one thread over the course of a single request. This method should return {@code true} if * the filter is currently executing within an asynchronous dispatch. * * @param request the current request * * @deprecated This method is no longer used to determine whether the servlet filter should execute, and will be * removed in a future update. It is here to support {@link * RequestTracingFilter#isAsyncDispatch(HttpServletRequest)}, which only remains to prevent breaking impls that * overrode the method. */ @Deprecated abstract boolean isAsyncDispatch(HttpServletRequest request); /** * 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(); } } /** * Implementation of {@link ServletRuntime} for Servlet 2.x environments. */ static class Servlet2Runtime extends ServletRuntime { @Override public boolean isAsyncRequest(HttpServletRequest request) { return false; } @Override public void setupTracingCompletionWhenAsyncRequestCompletes(HttpServletRequest asyncRequest, TracingState originalRequestTracingState) { throw new IllegalStateException("This method should never be called in a pre-Servlet-3.0 environment."); } @Override boolean isAsyncDispatch(HttpServletRequest request) { return false; } } /** * Implementation of {@link ServletRuntime} for Servlet 3+ environments that supports async requests. */ static class Servlet3Runtime extends ServletRuntime { @Override public boolean isAsyncRequest(HttpServletRequest request) { return request.isAsyncStarted(); } @Override public void setupTracingCompletionWhenAsyncRequestCompletes(HttpServletRequest asyncRequest, TracingState originalRequestTracingState) { // Async processing was started, so we have to complete it with a listener. asyncRequest.getAsyncContext().addListener( new WingtipsRequestSpanCompletionAsyncListener(originalRequestTracingState) ); } @Override boolean isAsyncDispatch(HttpServletRequest request) { // Do a string comparison to avoid pulling in the DispatcherType import. return "ASYNC".equals(request.getDispatcherType().name()); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy