Jersey Server Request/Response filter thread safe - jersey-2.0

I want to add some MDC logging to all my REST requests and I am using jersey. I have seen some examples of this online but I can't find any info on the thread safety of doing this:
https://coderwall.com/p/qjwyya/jax-rs-mapped-diagnostic-context-filter
#Provider
public class HttpMDCRequestListener implements ContainerRequestFilter, ContainerResponseFilter {
#Override
public void filter(ContainerRequestContext containerRequestContext) throws IOException {
MDC.put("test", "blah");
}
#Override
public void filter(ContainerRequestContext containerRequestContext,
ContainerResponseContext containerResponseContext) throws IOException {
MDC.clear();
}
Is there a new instance of this class for each request? I want to make sure I am clearing the MDC on the same thread as the request.
thanks

Related

How to send email from a servlet using threads or executor service?

Where executor service should be declared so it is available to other servlets and not new thread gets created for every new request
Can I do something like this and whenever need to send email, forward request to this servlet
Can you please suggest better design to use ExecutorService in servlet or any other way to send email from servlet?
public class EmailTestServlet extends HttpServlet
{
ExecutorService emailThreadPool = null;
public void init()
{
super.init();
emailThreadPool = Executors.newFixedThreadPool(3);
}
protected void doGet(HttpServletRequest request,HttpServletResponse response)
{
sendEmail(); //it will call emailThreadPool.execute();
}
public void destroy()
{
super.destroy();
}
}
Depends on whether CDI is available at your environment. It is available out the box in normal Jakarta EE servers, but in case of barebones servletcontainers such as Tomcat or Jetty you'd need to manually install and configure it. It's relatively trivial though and gives a lot of benefit: How to install and use CDI on Tomcat?
Then you can simply create an application scoped bean for the job like below:
#ApplicationScoped
public class EmailService {
private ExecutorService executor;
#PostConstruct
public void init() {
executor = Executors.newFixedThreadPool(3);
}
public void send(Email email) {
executor.submit(new EmailTask(email));
}
#PreDestroy
public void destroy() {
executor.shutdown();
}
}
In order to utilize it, simply inject it in whatever servlet or bean where you need it:
#WebServlet("/any")
public class AnyServlet extends HttpServlet {
#Inject
private EmailService emailService;
#Override
protected void doPost(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {
Email email = new Email();
// ...
emailService.send(email);
}
}
In case you find yourself in the unfortunate situation that you cannot use CDI, then you'll have to remove the #ApplicationScoped annotation from the EmailService class and reinvent the wheel by simulating whatever CDI is doing under the covers by manually fiddling with ServletContext#get/setAttribute() to simulate an application scoped bean. It might look like this:
#WebListener
public class ApplicationScopedBeanManager implements ServletContextListener {
#Override
public void contextCreated(ServletContextEvent event) {
EmailService emailService = new EmailService();
emailService.init();
event.getServletContext().setAttribute(EMAIL_SERVICE, emailService);
}
#Override
public void contextDestroyed(ServletContextEvent event) {
EmailService emailService = (EmailService) event.getServletContext().getAttribute(EMAIL_SERVICE);
emailService.destroy();
}
}
In order to utilize it, rewrite the servlet as follows:
#WebServlet("/any")
public class AnyServlet extends HttpServlet {
private EmailService emailService;
#Override
public void init() {
emailService = (EmailService) getServletContext().getAttribute(EMAIL_SERVICE);
}
#Override
protected void doPost(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {
Email email = new Email();
// ...
emailService.send(email);
}
}
See also:
What is recommended way for spawning threads from a servlet in Tomcat
How to run a background task in a servlet based web application?
Background process in Servlet

How to inject ResourceInfo in javax.servlet.Filter

I am trying to register time metrics based on the service method but not able to inject ResourceInfo.
I want to write some generic logic to register the time based on the service.
Here is my code:
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.ws.rs.container.ResourceInfo;
#WebFilter("/*")
public class MetricsGeneraterFilter implements Filter {
#Context
private ResourceInfo resourceInfo;
#Override
public void destroy() {
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
long startTime = System.currentTimeMillis();
chain.doFilter(request, response);
long elapsedTime = System.currentTimeMillis() - startTime;
System.out.println(resourceInfo.getResourceMethod().getName() + "--->" + elapsedTime);
}
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
}
How to inject ResourceInfo in javax.servlet.Filter?
I've used ContainerRequestFilter and ContainerResponseFilter to solve for this problem.
ContainerRequestFilter:
#Provider
public class RequestContextLoggingFilter implements ContainerRequestFilter{
public static final String REQUEST_START_TIME = "REQUEST_START_TIME";
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
requestContext.setProperty(REQUEST_START_TIME, Instant.now());
}
}
ContainerResponseFilter:
#Provider
#Priority(Priorities.USER)
public class ResponseLogFilter implements ContainerResponseFilter{
private Logger logger = LoggerFactory.getLogger(ResponseLogFilter.class);
#Override
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException {
try {
Instant end = Instant.now();
Instant start = (Instant) requestContext.getProperty(RequestContextLoggingFilter.REQUEST_START_TIME);
logger.info("Done executing request with request_execution_time={} ms",
Duration.between(start, end).toMillis());
}catch (Exception e){
logger.warn("error logging response time", e);
}
}
}
You can also use Jersey's Monitoring and Diagnostics module: https://jersey.github.io/documentation/latest/monitoring_tracing.html.
I haven't used it in production applications as it is in beta as of release >2.1
Try using a JAX-RS Filter instead. These operate just like Servlet filters but better as they are within the bounds of JAX-RS and can do many things that a Servlet Filters can't.
In order to do so, just make that class implement ContainerResponseFilter and ContainerRequestContext, and add it to your JAX-RS application (I.e. add the #Provider annotation or add it to your web.xml). Then implement the two methods. You can store the startTime in the RequestContext object's parameters.
I will edit this with a link to my own filter that does exactly this when I get a chance.

Spring Rest API interceptor add response header on each/every request

I am working with Spring 4 REST API annotation based configuration application. I want to add response header on each/every request once user is authenticate by JWT. I have created interceptor for that which looks as below:
public class AuthenticateInterceptor implements HandlerInterceptor {
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object object, Exception arg3)
throws Exception {
response.addHeader("afterCompletion", "afterCompletion header");
response.setHeader("afterCompletion", "afterCompletion header");
System.out.println("************** afterCompletion **************");
}
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object object,
ModelAndView modelAndView) throws Exception {
response.addHeader("postHandle", "postHandle header");
System.out.println("************** postHandle **************");
}
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object object) throws Exception {
System.out.println("************** preHandle **************");
return true;
}
}
My interceptor configuration is as below:
#Configuration
public class AdapterConfig extends WebMvcConfigurerAdapter {
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new AuthenticateInterceptor());
}
}
When I get JSON response I am not able the see the added header value which are added from interceptor. Any one help me what is the issue and how can I add header from interceptor for each/every request.
I didn't succeed in interceptors, Instead using Filters or WebFilter perfectly works:
#Component
public class ResponseHeaderWebFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
httpServletResponse.setHeader("CustomHeaderName", "SomeValue");
chain.doFilter(request, response);
}
}
In case you are using webflux reactive component, then :
#Component
public class ResponseHeaderWebFilter implements WebFilter {
#Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
exchange.getResponse()
.getHeaders()
.add("CustomHeaderName", "SomeValue");
return chain.filter(exchange);
}
}
If it can help you, I've managed it like this: https://stackoverflow.com/a/49431665/4939245
Look at second point
You can put the response header for each call in the application (this is for Spring annotation-based):
#Component
public class Filter extends OncePerRequestFilter {
....
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
//response.addHeader("Access-Control-Allow-Origin", "*");
//response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
response.setHeader("Cache-Control", "no-store"); // HTTP 1.1.
response.setHeader("Pragma", "no-cache"); // HTTP 1.0.
response.setHeader("Expires", "0"); // Proxies.
filterChain.doFilter(request, response);
}
}
I hope I was helpful!
You are almost doing same but would like to give you consitant way of achieving same. Please do following changes.
1) Add #Component annotation on AuthenticateInterceptor class. And you package containing this class should be in packages scanned list.
#Component
public class AuthenticateInterceptor implements HandlerInterceptor {
...
}
2) Autowire and inject instance of AuthenticateInterceptor like below.
#Configuration
public class AdapterConfig extends WebMvcConfigurerAdapter {
#Autowired
private AuthenticateInterceptor authenticateInterceptor;
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authenticateInterceptor);
}
}

When custom AuthenticationEntryPoint is enabled, PUT requests throw InsufficientAuthenticationException: Full authentication is required

This question is related to this one
I defined my own AuthenticationEntryPoint. When enabled, I receive an exception when trying to execute put requests:
org.springframework.security.authentication.InsufficientAuthenticationException: Full authentication is required to access this resource
But it doesn't happen otherwise.
Does anybody know why and how to fix it?
If it's needed more configuration information, let me know.
This is my configuration:
#Configuration
#Order(1)
public static class RestWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
...
#Override
protected void configure(HttpSecurity http) throws Exception {
...
http
.authorizeRequests()
.antMatchers("/rest/**").hasAnyRole(Sec.ADMIN,Sec.SUPER_USER)
...
.and().exceptionHandling().authenticationEntryPoint(restAuthenticationEntryPoint)
If I comment out the last line ("authenticationEntryPoint..."), my PUT requests work just fine.
I need to use that EntryPoint in order to prevent the redirection to the login form since this is a REST service.
My RestAuthenticationEntryPoint class is:
#Component( "restAuthenticationEntryPoint" )
public final class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {
#SuppressWarnings("unused")
private final Logger logger = Logger.getLogger(getClass());
#Override
public void commence(final HttpServletRequest request, final HttpServletResponse response, final AuthenticationException authException) throws IOException {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException.getMessage());
}
}

Multiple ContainerRequestFilter for Jersey

We are planning on using Jersey's reference implementation for our REST APIs. As a prototype effort, I was also playing around with the ContainerRequestFilters and I implemented multiple of them. Is there a way in which we can control the order in which these filters are executed?
The scenario that I am thinking over here is to ensure that the security filter must be the first one to run, and if required establish the SecurityContext and then execute other filters.
Yes you can control this with the javax.annotation.Priority attribute and the default javax.ws.rs.Priorities. For example if you wanted:
Logging filter always runs first
Authentication filter should run next
Authorization filter should run next
Custom filter should always run after others
You could do:
#Priority(Integer.MIN_VALUE)
public class CustomLoggingFilter implements ContainerRequestFilter
{
#Override
public void filter(ContainerRequestContext requestContext) throws IOException
{
// DO LOGGING HERE, THIS RUNS FIRST
}
}
#Priority(Priorities.AUTHENTICATION)
public class AuthenticationFilter implements ContainerRequestFilter
{
#Override
public void filter(ContainerRequestContext requestContext) throws IOException
{
String authHeader = requestContext.getHeaderString(HttpHeaders.WWW_AUTHENTICATE);
// DO AUTHENTICATION HERE, THIS RUNS SECOND
}
}
#Priority(Priorities.AUTHORIZATION)
public class AuthorizationFilter implements ContainerRequestFilter
{
#Override
public void filter(ContainerRequestContext requestContext) throws IOException
{
String authHeader = requestContext.getHeaderString(HttpHeaders.AUTHORIZATION);
// DO AUTHORIZATION HERE, THIS RUNS THIRD
}
}
#Priority(Priorities.USER)
public class MyAwesomeStuffFilter implements ContainerRequestFilter
{
#Override
public void filter(ContainerRequestContext requestContext) throws IOException
{
// DO AWESOME STUFF HERE, THIS RUNS LAST
}
}