views:

522

answers:

5

Hey guys, This is probably a very beginner level question. But I need to get hold of the request object in java code. I can't pass this object down to my code for certain reasons. Is there any way I can say something like: getCurrentHTTPServletRequest?

It is safe for me to assume that I am in a Servlet Context.

+6  A: 

Well you should pass it down if you need it. Anything else you do is going to be ugly, basically.

You could use a ThreadLocal variable - basically set the context for that particular thread when you get the request, and then fetch it later on. That will work so long as you only need to get at the request within the thread that's processing it - and so long as you don't do any funky asynchronous request handling. It's brittle though, for precisely those reasons.

However, I would strongly advise you to be explicit about your dependencies instead. Either pass the servlet request down, or just the bits that you need.

Jon Skeet
+1: for the *should pass it down*. Much more recommended than the ugly ThreadLocal hacks which I really wouldn't use as request threads can be pooled by the webcontainer, or you must really ensure that you remove it from the thread when finished. Too much work and nasty side-effects/
BalusC
It's not always possible to pass objects down. You may have to cross some APIs you have no control of. Even if you can change any API, it would be silly and inconvinient to declare a request argument in all your methods, and pass the request object everytime you call any method. ThreadLocal is fine as long as you know what you are doing.
irreputable
Then either the API isn't intented for the praticular purpose, or you're looking for a solution in the wrong direction. What about accessing it *from the other side* for example? I've done JSP/Servlet too long to confirm that there are enough better ways and that you don't necessarily need ThreadLocal stuff for this.
BalusC
@BalusC, you are absolutely correct in the cases when sane people have provided and chosen the frameworks to work with. If one is forced to some 'genious'-design, the 'lesser evil' is to be chosen. Of course, we can't know what the case is here - only that there are "certain reasons" :)
Bozho
A: 

Assuming the top-level servlet really is taboo for some crazy business-related reason, there is still the option of defining a ServletFilter to pre-view the request and stuff it into a ThreadLocal. Assuming that the web.xml is not also sacrosanct.

But I agree with Jon Skeet in that this would be very ugly. I'd code this up and then try to find a different job. :)

Actually, given the fact that a filter can totally wrest away control from the receiving servlet, you could use this technique to divert the code to a servlet of your own, do whatever you want, and THEN run the other, "official" servlet... or anything else along those lines. Some of those solutions would even allow you to deal correctly and robustly with your request data.

Carl Smotricz
+2  A: 

Jon Skeet said practically everything, but one clarification to his advice "just the bits that you need" - if you need your request parameters passed down, but you don't need a dependency on HttpServletRequest, pass request.getParameterMap().

And extending a bit on the ThreadLocal option - you can have a Filter which handles all incoming requests, and sets the request in a

public final static ThreadLocal<HttpServletRequest> httpServletRequestTL =
      new ThreadLocal<HttpServletRequest>();

Because you are setting it on each request (careful with the filter mapping), you won't have to worry about the servlet-container thread pool - you will always have the current request.

P.S. this is the logic behind the spring utility proposed by skaffman - I join him recommending the stable component, rather than making your own.

Bozho
+2  A: 

Assuming you're not able to pass the request object down the call stack, then some kind of sharing mechanism becomes necessary, which is not ideal, but sometimes necessary.

Spring provides the RequestContextFilter for just this purpose. It uses ThreadLocal, and allows the code to fetch the current request via RequestContextHolder. Note that this filter does not require you to use any other part of Spring:

Servlet 2.3 Filter that exposes the request to the current thread, through both LocaleContextHolder and RequestContextHolder. To be registered as filter in web.xml.

This filter is mainly for use with third-party servlets, e.g. the JSF FacesServlet. Within Spring's own web support, DispatcherServlet's processing is perfectly sufficient.

If you're going to use ThreadLocal, then better to use an existing, working solution, rather than risk bugs creeping in, which ThreadLocal code is prone to.

skaffman
+1  A: 

There is no Servlet API to do this. However, Tomcat does provide an API call to do this,

   HttpServletRequest request = (HttpServletRequest)org.apache.catalina.core.ApplicationFilterChain.getLastServicedRequest();

This will get the last request passed to a servlet for servicing from the current thread.

For this to work, the Tomcat must be in Strict Servlet Compliance mode. If not, you need to enable it by adding this JVM parameter,

  org.apache.catalina.STRICT_SERVLET_COMPLIANCE=true
ZZ Coder