I read the servlet-3.0 specification and have got one question about the ServletRequest object. Currenctly I have a filter chain
public class MyFilter implements Filter{
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain filterChain) throws IOException, ServletException {
//do filter
}
}
after doing filters the javax.servlet.Servlet's
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException;
comes into play. Is it reliable that both in the filter's method and the service method operate on the same object reference? The servlet specification said this:
Each request object is valid only within the scope of a servlet’s
service method, or within the scope of a filter ’s doFilter
method, unless the asynchronous processing is enabled for the
component and the startA sync method is invoked on the request object
But it;s not obvious to me that the ServletRequest object is a singleton per one request handling.
Upd: To be more specific, I need to return the HttpSession instance within Filter's doFilter method and Servlet's do_HttpMethod_ method. Is it always the same? I mean httpServletRequest.getSession()
A container uses a single request object for a given request. However any filter can wrapper the request object so your filter or servlet may be getting a wrapper depending on what other filters do. Usually as an app developer you would know if this is the case. If no wrappers are used the filter and servlets get the same request object.
For info on request wrappers see:
http://docs.oracle.com/javaee/7/api/javax/servlet/http/HttpServletRequestWrapper.html
So when you call getSession() you may get the container implementation of the method or that provided by a wrapper. However note that an HttpServletRequestWrapper object provides a getRequest() method which returns the request object it wraps so you can recurse through wrappers until you get the original and then call it. Lots of examples how to do this on the web.
ServletRequest is an interface and the same is used in doFilter method as well as service method. So both are going to return the same session object (if you call getSession()).
Servlet as well as Filter uses same interface so it's going to behave same way. I am not sure why you are curious to know if it's singleton ? May be you can check servlet specification to know more about it.
Related
I'm working on a RESTful API, using Apache CXF as my JAX-RS implementation. I have a POST endpoint that's supposed to receive a request with three parameters. Here's a snippet of my code (modified and shortened):
#Path("endpoint_path")
public class MyResource {
#Context
private HttpServletRequest request;
#POST
#Produces(MediaType.TEXT_HTML)
#Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response postEndpoint(#QueryParam("param1") String param1,
#FormParam("param2") String param2,
#FormParam("param3") String param3) {
(use request as input for some library)
}
}
Inside that method, param2 and param3 both have the expected values, but if I check the request object's parameters (by using request.getParameterNames()), I only get one parameter -param1- instead of all three. I know for sure that I'm receiving all 3 parameters, param1 as a query parameter, and param2 and param3 as form parameters, because as I just said, I get their values passed as method parameters. They just don't seem to exists inside the request object.
This puzzled me so much, that I created a Filter that only does one thing, it peeks inside the request for the parameter names and does nothing else:
public class TestCXFPostParamsFilter implements Filter {
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {
servletRequest.getParameterNames();
filterChain.doFilter(servletRequest, servletResponse);
}
(init() and destroy() empty methods)
}
and in my web.xml file, I set the filter to apply to every request to my endpoint. Now here's where things get weird - for some reason, that makes everything work, by which I mean, if I check the request object back in the endpoint method, it'll contain all three expected parameters. What sorcery is this?
As a side note, some of you may be wondering why would I bother to check the request object, when I just said I have access to the parameter values that are passed to the method by CXF's servlet? The answer is that I'm using a library that expects you to pass the request object to it, instead of just the necessary values. So I really need the request to keep its parameters inside (like I always assumed it would).
Finally, I'm using Java 6, and CXF 2.7.10 (which comes with Apache Camel CXF 2.13.0). And yes, those are more or less set in stone for all intents and purposes, so if the reason all of this is happening is because of a bug in one of these pieces, I'm stuck with an useless filter as a "solution".
I use ModelAndView objects as all people do:
ModelAndView result = new ModelAndView("view");
result.addObject("requests", requestsService.getListByBackoffice(filter, page, Config.RECORDS_PER_PAGE));
But I noticed that I have a couple of objects that I use always in most of the views.. So the question is - is there any solutions to create some kind of default assigned objects that are passed to view automatically?
Thank you
You can register a HandlerInterceptor with your DispatcherServlet. You then implement the postHandle() method:
public class CustomInterceptor extends HandlerInterceptorAdapter /* which implements HandlerInterceptor */ {
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
modelAndView.addObject("myObject", new Object());
// add as many as you wish
}
}
NOTE: The ModelAndView object may be null. This may occur if your handler method was writing to the response body directly, for example with #ResponseBody.
Depending on the url pattern you used when registering the Interceptor, the postHandle() will get called and populate your model with any objects you want.
You can also register a servlet Filter (in web.xml or WebApplicationInitializer). The filter simply adds the request attributes before dispatching to the servlet.
public class CustomFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
request.setAttribute("myObject", new Object());
chain.doFilter(request, response);
}
// ... init and destroy methods
}
NOTE: At some point during the request lifecycle, Spring adds all attributes in the model to your request attributes.
The disadvantage here is that you add the attributes whether or not your #Controller worked, as the Filter is called before Spring's DispatcherServlet. Also, the Filter is managed by your servlet container (workarounds exist) and therefore it's difficult to inject Spring beans into it.
first solution:
I have not tried such but can do like creating ModelAndView object in Constructor or somewhere which you call always, set object which you always want to pass as default there only.
call setViewName() in respective methods and add respective objects which you want to set.
second solution:
write one method which is adding that default object and call that method wherever you need (nothing but what interceptor do).
I understand that the first call to getParameter will read the postdata content, if any.
Is there a way for me to limit how much postdata content would be processed into the RAM, or am I going to need to override the getParameter* methods for that to be accomplished?
I am not interested in making this a server-wide setting.
or am I going to need to override the getParameter methods for that to be accomplished?*
Yes.
For that you can use a homegrown HttpServletRequestWrapper which is injected by a Filter.
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
chain.doFilter(new MyPostDataLimitingRequest((HttpServletRequest) request), response);
}
I do not believe there is a way to limit through the existing getParameter(), which is a convenience method, without extending the servlet or adding a listener to break it down for you.
You can circumvent this by parsing the input stream within your servlet directly using getInputStream() or getReader(), but I believe this invalidates further calls to getParameter() for the rest of that request; you'll need to consume the rest of the input through your selected method.
It's not elegant, but it works.
I will need to implement my own version of HttpSession in Java. I have found very little information which explains how achieve such a feat.
I guess my problem is - how do I override the existing HttpSession no matter the application server's implementation?
I did run across a quality but rather old read which helps me achieve my goal - http://java.sun.com/developer/technicalArticles/Servlets/ServletControl/
Are there any other approaches?
Its two ways.
"Wrapping" the original HttpSession in your own HttpServletRequestWrapper implementation.
I made this a short time ago for clustering distributed sessions with Hazelcast and Spring Session.
Here is explained pretty well.
First, implement your own HttpServletRequestWrapper
public class SessionRepositoryRequestWrapper extends HttpServletRequestWrapper {
public SessionRepositoryRequestWrapper(HttpServletRequest original) {
super(original);
}
public HttpSession getSession() {
return getSession(true);
}
public HttpSession getSession(boolean createNew) {
// create an HttpSession implementation from Spring Session
}
// ... other methods delegate to the original HttpServletRequest ...
}
After, from your own Filter, wraps the original HttpSession, and put it inside the FilterChain provided by your Servlet Container.
public class SessionRepositoryFilter implements Filter {
public doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
HttpServletRequest httpRequest = (HttpServletRequest) request;
SessionRepositoryRequestWrapper customRequest =
new SessionRepositoryRequestWrapper(httpRequest);
chain.doFilter(customRequest, response, chain);
}
// ...
}
Finally, set your Filter at the beginning in the web.xml to ensure it performs before any other.
The second manner to achieve it is providing to your Servlet Container your custom SessionManager.
For example, in Tomcat 7.
Create a new class, and implement HttpSession:
public class MyHttpSession implements javax.servlet.http.HttpSession {
// and implement all the methods
}
Disclaimer: I have not tested this myself:
Then write a filter with a url-pattern of /* and extend HttpServletRequestWrapper. Your wrapper should return your custom HttpSession class in getSession(boolean).
In the filter, use your own HttpServletRequestWrapper.
It doesn't seem like it's easily doable in a portable fashion that would work among different containers, since the HttpSession implementation is provided by the J2EE container.
However, to achieve a similar result, you can implement a javax.servlet.Filter and javax.servlet.HttpSessionListener and in your filter, wrap the ServletRequest and ServletResponse, such as described in Spring Boot with Hazelcast and Tomcat.
Why does the service() method in the Servlet interface not return an instance of ServletResponse but rather work on the ServletResponse object provided by the container?
In simple words why is the service method of the Servlet interface like:
public void service(ServletRequest request, ServletResponse response);
and NOT like:
public ServletResponse service(ServletRequest request);
If the response object is provided by the servlet container, it can control how things like buffering are handled. For example, suppose you created your own ServletResponse - how would the container manage the ability to stream the response if it's over a certain length, instead of buffering the data?
It uses a Response the container builds partially for it. It doesn't build the response out of whole cloth. It'd have to be an argument in any event.