Alternative to requestDestroyed in ServletRequestListener - java

I have multiple servlets in my web app. And I want to perform a specific action each time a request comes to MyServlet (only) and not when request is for any other servlet. Overriding destroy isn't going to solve this.
If I write a custom ServletRequestListener, that action will be performed for all requests, if I put that action in requestDestroyed method, irrespective of which servlet in my web app is being called.
So, does writing requestDestroyed method as a part of servlet itself like below solves this problem ? Or is there any other/better way?
public class MyServlet implements HttpServlet {
public void init(ServletConfig config) throws ServletException {
//init stuff
}
public void service(ServletRequest req, ServletResponse res)
throws ServletException {
try {
//do some stuff
} finally {
requestDestroyed(request);
}
}
private void requestDestroyed(HttpServletRequest request) {
//some clean up stuff only for this particular servlet
}
}

Related

How to add objects into Model after each request (Spring Boot)

I'm developing a web application with Java and Spring Boot. What I would like to do is to add an object into the Model every time a request is received. Let me explain better what I'm doing and why I need it.
The application is an eCommerce and I need every time a page is loaded the number of items inside the cart and the number of notifications a user has got. These information are displayed inside the menu in all the pages of the web app. Right now I'm requesting these information to through an ajax call after the page has been loaded. I would like to automatically add these information inside the Model and render and return all the pages with them already present without making any further request.
I googled it and I found out that a way to solve this problem is to use an Interceptor.
I implemented it following this tutorial but the only problem is that preHandle, postHandle and afterCompletion get called not only with the page requests but also with other kind of content like images, videos etc.
#Component
public class ProductServiceInterceptor implements HandlerInterceptor {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("Pre Handle method is Calling: " + request.getRequestURI());
return true;
}
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("Post Handle method is Calling");
}
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception exception) throws Exception {
System.out.println("Request and Response is completed");
}
}
When registering your interceptors in WebMvcConfigurerAdapter, you can also define a path pattern to include or exclude.
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new YourInterceptor()).excludePathPatterns("/path/to/your/static/resources/*");
}
Full example is available here : https://www.concretepage.com/spring/spring-mvc/spring-mvc-handlerinterceptor

Vaadin RequestDispatcher don't lead to JSP file in webapp dir

I've done my java web app in Java EE with HttpServlet and JSP. I normally map my Servlet like this:
#WebServlet(urlPatterns = "/main")
public class MainServlet extends HttpServlet{
I do my servlet stuff and would like to pass data to JSP file like this:
RequestDispatcher dispatcher = req.getRequestDispatcher("/main.jsp");
dispatcher.forward(req, resp);
The main.jsp is in my web app folder (I use IntelliJ Idea).
The question is, I've initially made my UI with Vaadin 8. Using following:
#Theme("mytheme")
#CDIUI("users")
#SuppressWarnings("serial")
public class Vaadin extends UI
and then override init.
Now I would like to add a single HttpServlet and override doGet and then call the dispatcher to forward data to jsp. Here's the problem adding Vaadin somehow broke the path to tsp, as jsp does not display, instead a standard vaadin
Request was not handled by any registered handler.
appears, I know the servlet was mapped properly as the servlet starts and does work, what does not work is the running the JSP file.
Can anyone advise?
It seems that you need to implement yet a WebFilter to process JSP. Your dispatcher forwards the request but it is then a request that is again handled by some filter by Vaadin I guess. Also I am not sure if you need any servlet and/or dispatcher (not sure what your actual use is).
Anyway, with WebFilter it is possible to intercept this processing. Check the following example
#WebFilter(filterName="jspFilter", urlPatterns="*")
public class JspFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
try {
HttpServletRequest hreq = (HttpServletRequest)request;
String path = hreq.getPathTranslated();
if(path.toLowerCase().endsWith(".jsp")) {
try(Writer writer = response.getWriter();
Reader reader = new FileReader(path) ) {
processJsp(reader, writer);
return;
} catch (Exception e) { /* TODO: handle exception */};
}
} catch (Exception e) { /* TODO: handle exception */};
chain.doFilter(request, response); // forward to filter chain by default
}
#Override public void destroy() {}
#Override public void init(FilterConfig filterConfig)
throws ServletException {}
}
This filter checks all request. If URI (here checked from translated/absolute path) is ending with .jsp it is processed with processJsp(reader, writer) that you might want to implement to do the forwarding to JSP parser or so.

Where to clear the requestId from MDC

I'm trying to add a requestId to my web app's logs, as shown here.
public class MDCFilter implements ContainerRequestFilter, ContainerResponseFilter
{
private static final String CLIENT_ID = "client-id";
#Context
protected HttpServletRequest r;
#Override
public void filter(ContainerRequestContext req) throws IOException
{
Optional<String> clientId = Optional.fromNullable(r.getHeader("X-Forwarded-For"));
MDC.put(CLIENT_ID, clientId.or(defaultClientId()));
}
#Override
public void filter(ContainerRequestContext req, ContainerResponseContext resp) throws IOException
{
MDC.remove(CLIENT_ID);
}
private String defaultClientId()
{
return "Direct:" + r.getRemoteAddr();
}
}
The problem with this is that it sets and removes requestId from MDC in the above filter. I also log the bodies of the responses my application generates with a WriterInterceptor. The problem is that, since interceptors run after filters, by the time my WriterInterceptor executes, there is no requestId in MDC.
My question is, is it ok to call MDC.clear() at the end of WriterInterceptor (which feels somehow hacky), or is there a better way of achieving this?
I'm having the same problem. This is how it currently works in code I'm developing
#Order(Ordered.HIGHEST_PRECEDENCE)
public final class RequestFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
try {
//stuff
chain.doFilter(request, response);
} finally {
// this clears a specific entry from the MDC but not the entire MDC
RequestContext.clear();
}
}
}
I could clear the entire MDC in the finally block here...but I don't know when Spring logs exceptions. Would I be clearing too early? My new plan is to clear the MDC when I start a request.
I'm not sure if this is a full answer, but clearing the MDC in my highest precedence filter should work.

How to get Cookies from ServletContextListener?

i am new in Servlet and JSP and i want to grab all the cookies once my web app is running so i am using ServletContextListener to deploy what inside it once my web app is run !, so how can i get all cookies within it ?
i am trying to do the following :
public class listener implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent sce) {
HttpServletRequest request ;
Cookie s[]=request.getCookies();
}
#Override
public void contextDestroyed(ServletContextEvent sce) {
}}
Probably you don't need all the cookies [ie cookies of all users], but you need cookies of particular request. You can get them inside HttpServlet's doGet() or doPost() methods, depending on the request type:
public class TestServlet extends HttpServlet {
public void doGet(HttpServletRequest request,HttpServletResponse response)
throws ServletException, IOException {
Cookie[] cookies = request.getCookies();
//...
}
}

Avoiding the endless loop in JSP servlet mapping

I've got this issue, recently I read about the REST arquitecture and it makes a perfect sense, so I'd like to achieve a RESTful web application.
Now, I'm following the Front Controller pattern that means that all of the URL mappings go to the controller.java servlet, I map the by specific URLs, not by using the /* wildcard,
the controller implements the four HTTP methods POST,GET,PUT,DELETE, each method calls the controllers service method and there I determine based on the HttpServletRequest and pathInfo the action to execute.
Controller.java
#Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
IAction action;
View view;
try {
action = ActionFactory.produceAction(req);
view = action.execute(req, resp);
switch (view.getDispatchMethod()) {
case REDIRECT:
resp.sendRedirect(resp.encodeURL(view.getResource()));
break;
case FORWARD:
req.getRequestDispatcher(view.getResource()).forward(req, resp);
break;
case INCLUDE:
req.getRequestDispatcher(view.getResource()).include(req,resp);
break;
default:
}
} catch (ActionFailedException uae) {
req.setAttribute("ActionName", "Action");
req.setAttribute("FailCause", uae.getMessage());
req.getRequestDispatcher(VIEW_FAIL.getResource()).forward(req, resp);
}
}
#Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
this.service(req, resp);
}
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.service(req, resp);
}
#Override
protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.service(req, resp);
}
#Override
protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.service(req, resp);
}
I've run into a particular issue when loading a specific order by the URI /orders/*, it is mapped to the controller servlet, the the action is executed and I load the appropriate order the action returns a View.java class
//ommited accessors and mutators for brevety.
public class View {
public enum DispatchMethod {
INCLUDE, FORWARD, REDIRECT
}
private DispatchMethod dispatchMethod;
private String resource;
public View(DispatchMethod dispatchMethod, String resource) {
this.dispatchMethod = dispatchMethod;
this.resource = resource;
}
}
Then the request is dispatched according to the getDispatchMethod() of the returned view.
Now, here is where the loop gets triggered, I use the following URL, myapp/orders/78965 /orders/* gets mapped to controller.java the appropriate action is executed and the correct order is found by the pathInfo() the returned view is new View(View.DispatchMethod.FORWARD,"order_details.jsp") the problem is that with the three available dispatch methods REDIRECT,FORWARD and INCLUDE a request is re-triggered on the URL and so on and on and on I never reach the order_details.jsp that renders the data.
So, how would you avoid the looping, as I'd like to preserve the URI displaying the order number I use the forward method, also, I'd like to do it using servlets, I've heard of the UrlRewriteFilter maybe in the future, but right now, how would it be done using "Plain Vanilla" since I'm using the Front Controller pattern, will it be necessary to add an additional servlet in the /orders/ URI ?
Any help or insights is truly appreciated.
EDIT 1:
Pasted the source code of the controller, a very basic one, I have my suspicions that the way the service method calls all of the overriden do[Method] of the servlet is triggering the loop and that it may be solved by splittig them.
Implementing a RESTful HTTP interface in Java is a lot easier using a JAX-RS implementation like RESTEasy or Jersey.
Using a Front Controller to dispatch requests to the right resource is a good approach, it's exactly the approach taken by these JAX-RS frameworks. I fear you may be re-inventing the wheel here by writing a bespoke URL parsing and dispatching mechanism when this can be taken off-the-shelf.
JAX-RS is a lightweight way to expose resources. By using a couple of simple annotations you can expose a REST interface without any plumbing required. For example:
public class Order {
#GET
#Path("/orders/{orderId}")
#Produces("text/html")
public void getOrder(#Context HttpServletResponse response,
#Context HttpServletRequest request,
#PathParam("orderId") String orderId) throws ServletException, IOException {
// ... create view and add to request here
request.getRequestDispatcher("orders.jsp").forward(request, response);
}
}
You can see how simple it is to attach this class to a URL path (using the #Path annotation), and how easily you can parse values from the URL using #PathParam. Since you get all the plumbing/dispatching/parsing off-the-shelf, you can concentrate on the bits of your app that are specific to your domain (such as what an order contains).

Categories

Resources