IllegalStateException when using Spring RequestContextHolder - java

I am using a RequestContextHolder in a filter to record a piece of data, and want to access it in a POJO (wired up via Spring) later. I'm getting an exception which suggests I'm doing something wrong here, would appreciate any guidance on what that is.
Filter code (in a doFilter() method, whose logging confirms it's being called):
RequestAttributes attrs = RequestContextHolder.getRequestAttributes();
if (attrs == null)
{
logger.info("Creating new ServletRequestAttributes");
attrs = new ServletRequestAttributes(servletRequest);
}
attrs.setAttribute("my_attr", "hello there!", RequestAttributes.SCOPE_REQUEST);
RequestContextHolder.setRequestAttributes(attrs);
POJO code:
RequestAttributes attrs = RequestContextHolder.getRequestAttributes();
if (attrs != null && attrs.getAttribute("my_attr", RequestAttributes.SCOPE_REQUEST) != null)
{
String myAttr = (String) attrs.getAttribute("my_attr", RequestAttributes.SCOPE_REQUEST);
logger.debug("Got it: ", myAttr);
}
I am seeing this exception coming from Tomcat though:
java.lang.IllegalStateException: The request object has been recycled and is no longer associated with this facade
at org.apache.catalina.connector.RequestFacade.getAttribute(RequestFacade.java:259)
at org.springframework.web.context.request.ServletRequestAttributes.getAttribute(ServletRequestAttributes.java:98)
at com.mycompany.MyClass(MyClass.java:50)
I do wonder if having the "set data" in a filter, and "get data" via the real work of the request could be in play here, but not sure how best to accommodate that, if it even is relevant?

The error is likely caused by the fact that you're making Spring maintain a thread-local handle to a request object that is no longer valid. The details probably don't matter all that much since a different approach is in order.
One of the following will take care of automatically setting and clearing thread-local state properly: DispatcherServlet, RequestContextListener or RequestContextFilter. You need to figure out which one makes the most sense for how Spring is used with your app. Your filter and POJO code shouldn't need to make use of classes like RequestContextHolder directly. What should happen is that you declare a proxied, request-scoped bean for the attribute you want to access:
<bean id="myAttr" scope="request">
<aop:scoped-proxy/>
</bean>
Then, declare the bean for your POJO along with its dependency on the request-scoped bean:
<bean id="myPojo">
<property name="myAttr" ref="myAttr"/>
</bean>
See: Request, session, and global session scopes
Spring should take care of all the details...

Related

Request scoped bean is always available when running code outside of request scope in Spring 4

Stuck on this thing in Spring 4, probably the same will be for 5.
So, what I have:
Spring Boot 1.5 web app
Request scoped bean:
#RequestScope
#Component
public class APIAction { ... }
Code which accesses this component from threads related or not related to webrequest:
private final ObjectProvider<APIAction> apiAction;
apiAction.getIfAvailable()...
When it runs in Thread bounded to web request everything is fine. But when I invoke it from daemon thread I expect to get null, exception or something else. Instead I'm receiving some proxy object which can't be tested for null, or any kind of state indicating that bean is really available. If I'll try to invoke any bean method, I'll get exception finally saying accessing to bean outside of thread bounded to web request.
So the question is, am I using it wrong? Right now, I'm checking request scope before accessing to bean by invoking this: RequestContextHolder.getRequestAttributes() != null, which is really ugly, and I need all the time to tell people why they should use it like this.
And bonus question, is it possible actually to instantiate that bean in threads without request bound?
TL;DR: You can't use ObjectProvider.getIfAvailable() to check if in request scope.
Use if (RequestContextHolder.getRequestAttributes() != null) instead.
As the javadoc of ObjectProvider says:
A variant of ObjectFactory designed specifically for injection points, allowing for programmatic optionality and lenient not-unique handling.
For singleton beans, ObjectProvider<APIAction> is an alternative to #Autowired(required = false) List<APIAction> with methods that better represent the purpose.
For prototype beans, it allows the on-demand creation of the prototype, including optional constructor arguments.
However, it's all about the existence of the bean, i.e. about whether the bean has been registered (and how many). Any #Component (or other) annotated class is registered by the component scanning, regardless of the bean scope.
The #RequestScope bean exists, so the code could be changed to #Autowired private final APIAction apiAction;, and it would always be non-null.
The fact that the object referred to by apiAction is a proxy that will apply method calls to different instances depending the the request context is besides the point.
When you call an APIAction method, you will get an IllegalStateException saying:
No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
Internally, a #RequestScope annotated class has a Scope of type RequestScope, and the javadoc says:
Relies on a thread-bound RequestAttributes instance.
It does this by calling RequestContextHolder.currentRequestAttributes(), which throws the above exception.
Solution: To check if you are in a request context, call RequestContextHolder.getRequestAttributes() and check for null return value.

How spring session beans saved ? replicating spring session beans via Hazelcast

I'm trying to integrate Hazelcast (lasted version - 3.3) session replication.
Our infrastructure consists of :
Apache 2.0 server for the load balancing
Tomcat 7 servers serving our web application
Our main reasons are:
Duplicate user session for high availability
Atmosphere web-socket PubSub servlet need share the same data in order to make full
broadcasting
integrating Hazelcast to our Environment:
each of the tomcat servers will serve as Hazelcast member
basically Hazelcast WebFilter is the first one that executes and its
wrap with : WebFilter->HazelcastSession->setAttribute() implements
HttpSession interface
each time setAttribute is called Hazelcast sync the session attribute
with the rest of the cluster members.
now - its seems like every spring bean we injecting scoped as session bean don't get replicated .
as a workaround :
Save only basic session information via #Context annotation
Dont use Spring session scope , only Singletons and inject the HazelcastInstance
I can Wrap the relevant data as Hazelcast structures
Also, when i looked on other stackoverflow i saw the following : Spring "session" scope of a bean?
The Spring session does not exactly match the HttpSession, and even
the Spring documentation on the #SessionAttributes annotation says
that it might be stored in the session or "some conversational
storage". I got that from [The Spring docs for 2.5][1] I've basically
quit trying to make sense of it, and just got on with my life, if I
want something stored in the HttpSession, I just have Spring inject
the HttpSession to me, assuming you're using Spring MVC its pretty
easy, instructions on the same page.
[1]:
http://static.springsource.org/spring/docs/2.5.x/reference/mvc.html
Its seems strange , Does Spring session beans not exactly match the HttpSession.setAttribute ?
How spring know how to #Inject the proper bean ?
Maybe Spring save the Beans in an internal data storage and only in
the Injection phase Spring getting the proper element using the same
session id attribute and bind the proper bean.
is there any way to control this behavior ?
Update :
debugging spring-web -> ServletRequestAttributes-> is using the
Server impl HTTPSession (For example - in Dev Jetty - org.eclipse.jetty.server.session.HashedSession)
this way the Bean is update in the HTTPSession but skipping the
HazelcastSession :-(
/**
* Update all accessed session attributes through {#code session.setAttribute}
* calls, explicitly indicating to the container that they might have been modified.
*/
#Override
protected void updateAccessedSessionAttributes() {
// Store session reference for access after request completion.
this.session = this.request.getSession(false);
// Update all affected session attributes.
if (this.session != null) {
try {
for (Map.Entry<String, Object> entry : this.sessionAttributesToUpdate.entrySet()) {
String name = entry.getKey();
Object newValue = entry.getValue();
Object oldValue = this.session.getAttribute(name);
if (oldValue == newValue) {
this.session.setAttribute(name, newValue);
}
}
} catch (IllegalStateException ex) {
// Session invalidated - shouldn't usually happen.
}
}
this.sessionAttributesToUpdate.clear();
}
thanks in advance ,
elad.

Spring MVC Controller Design

We are migrating a struts application over to Spring MVC and utilizing the #Controller annotation to direct pages to various method calls.
I'm having trouble determining a good strategy for reuse though.
We basically do the same things in many of our pages:
prepareView(..., ...); //Various params -- could likely be standardized
if (!allowedToView()) {
mav.setViewName(injectedErrorPage);
}
performBusinessLogic(..., ...); //Various params -- not seeing how to standardize
persistEntities();
finalizeView(..., ...); // Various params -- could likely be standardized
What strategies are used for creating a final method which will allow the developers to "forget" about these processes? I'd thought about making an abstract class, but there really isn't a way I'm seeing to "standardize" this due to differences in what each method will take.
For instance we have the following:
#RequestMapping("params="assign", method=RequestMethod.Post)
public ModelAndView assign(#SessionAttribute(value="sessionAttr") Pojo pojo,
#ModelAttribute("command") CommandPojo commandPojo,
BindingResult result) {
//Follows pattern above
}
#RequestMapping()
public ModelAndView filterResults(#SessionAttribute(value="sessionAttr") Pojo pojo,
#RequestAttribute("requestAttr") String requestAttr,
#ModelAttribute("command") CommandPojo2 commandPojo2,
BindingResult result) {
//Follows pattern above
}
Having a final method would require this to be broken into two POJOs (which would then call the descriptive functions). My immediate concern there is how do we deal with different parameters coming into this final method? I don't see any way to handle this situation.
It'd be nice if we could still have this "final" method with protected functions which we could override where needed.
I have the same problem as you. I don't have a clean solution yet, but I believe that I made some progress so I thought I'd share with you what I have found so far.
I explored the use of interceptors as suggested by three_cups_of_java, but I run into various problems (described below). Currently I am trying to use a custom AnnotationMethodHandlerAdapter, but I am not done yet with this effort.
Interceptors
Since the interceptors don't have access to the controller object that they intercept (correction: they do have access to it, but with limited control over the execution flow), the controller and the interceptor have to communicate through objects in the session.
Here is a somewhat simplified example of what I mean:
In our old architecture, we have our own base controller that everyone extends. It itself extends MultiActionController, and adds some custom behavior - like in your example, updating a server-side view after post request before invoking the handler method. This works because all the controllers provide an implementation of a template method (e.g. getViewKeyInSession()).
Thus, the custom code in the base controller looks roughly like this:
// inside handleRequestInternal method
if (request.getMethod().equals("POST") {
updateViewAfterPost (session.get(getViewKeyInSession());
}
return super.handleRequestInternal();
Now, when we moved this code to the interceptor, we run into several problems:
The interceptor can't invoke getViewKeyInSession(), forcing us to use the same session key for all controllers (not good), or adhere to some convention that the session key for the view is based on the url or a param of the request (so far this is not good either).
Individual controllers can no longer override the behavior of updateModelAfterPost. This is usually not necessary, but unfortunately it was necessary for some controllers.
If the controller provides an implementation of updateModelAfterPost and wants to signal to the interceptor that it is not interested in the interceptor's help, it needs to do so by putting a marker object in the session for the interceptor to look at, and it needs to do it during the previous GET request (also not good and not flexible).
Using a Custom AnnotationMethodHandlerAdapter
Currently I am looking at specifying the DefaultAnnotationHandlerMapping directly in my xml (instead of mvc:annotation-driven) and then supplying it with a custom AnnotationMethodHandlerAdapter.
As I said earlier, I haven't made enough progress to present full results, however the direction that I am aiming at is this:
I think of AnnotationMethodHandlerAdapter as a Spring-supplied MultiActionController, but for pojo controllers. For example, I already know how to plug to it my own method resolver (see this question) and other Spring goodies.
This adapter has several methods that you can override, such as
invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, Object handler),
and maybe
handle(HttpServletRequest request, HttpServletResponse response, Object handler)
as well.
In your custom code, you can inspect the handler class, and then act accordingly. To continue my previous example, if the handler class has a method updateViewAfterPost or if it implements a certain interface, then you can invoke that method, and then call super to let spring proceed with the regular invocation. Thus, the code looks roughly like this:
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) {
// inspect handler object, look for marker interface, methods and/or annotations
// perform pre-processing on the handler object
// e.g. handler.updateViewAfterPost(request, response)
ModelAndView mav = super.handle (request, response, handler);
// post-processing on the handler object
return mav;
}
(Of course, this is just a toy example. In real code you'll need better exception handling)
UPDATE:
I tried the above strategy with a custom AnnotationMethodHandlerAdapter, and it indeed works. I used a marker interface on my pojo controller, and introduced only one new method named updateModelAfterPost to the life-cycle, and it works as expected.
There are several small caveats that I ran into, mainly because I was combining the old ways with the new ways in the same mvc context. Below you can see the changes I made to the xml context, followed by a list of the issues that I think are worth highlighting.
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="order" value="2" />
</bean>
<bean class="com.sample.MyAnnotationMethodHandlerAdapter">
<property name="order" value="2" />
</bean>
<bean class="com.sample.MySimpleControllerHandlerAdapter" >
<property name="order" value="1" />
</bean>
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="order" value="1" />
<property name="mappings">
<props>
...
</props>
</property>
</bean>
As mentioned in the comment, I unrolled the <mvc:annotation-driven> short-hand. I had to explicitly define two handler mapping, and also define two handler adapters.
Unfortunately in my legacy code some controllers are transcational and are proxied by cglib. The AnnotationMethodHandlerAdapter doesn't cope well with that, therefore I set the order of elements such that the legacy handler mapping and handler adapter act first, and the annotation-based handler mapping and handler adapter act second.
I had to define explicitly Spring's SimpleControllerHandlerAdapter, but I also had to extend it with my own class, because it doesn't implement the Ordered interface.
I had a problem defining the validator, because I didn't have the jar for jsr-303. Therefore I dropped the declaration of validators and conversion service. The above xml snippet is exactly what I use, it is not a trimmed-down version simplified for the sake of the answer.
and finally, here is the code for the relevant classes:
package com.sample;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter;
public class MyAnnotationMethodHandlerAdapter extends AnnotationMethodHandlerAdapter {
protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (handler instanceof MyMarkerInterface) {
MyMarkerInterface handler2 = (MyMarkerInterface) handler;
handler2.updateModelAfterPost(request);
}
return super.invokeHandlerMethod(request, response, handler);
}
}
package com.sample;
import org.springframework.core.Ordered;
import org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter;
public class MySimpleControllerHandlerAdapter extends SimpleControllerHandlerAdapter implements Ordered {
private int order = 0;
public int getOrder() {
return order;
}
public void setOrder(int order) {
this.order = order;
}
}
Could you implement a base class as you are suggesting and force a Template Method design pattern and also to borrow from what Nix said in his earlier comment to your question about leveraging a parameter collection in this base class?
Does that help?
If the parameters are varying from function to function I think #Nix suggestion of parameter collection is a good one. Alternatively you could use var arg of objects. But you might need to have a check to see if all parameters are present before a function is called like a Pre condition check.
Or maybe a combination of both like, you would know that some of the parameters are always needed and others optional. So use varargs for the optional likethe following for filterResults
public ModelAndView filterResults(#SessionAttribute(value="sessionAttr") Pojo pojo,
#RequestAttribute("requestAttr") String requestAttr,
#ModelAttribute("command") CommandPojo2 commandPojo2,
Object...restOfParameters){}
This could be combined with the template pattern that is disscussed earlier.
If you want reusability you really should look into spring webflow, if you haven’t already. In short, webflow is an advanced spring mvc contoller that allows better separation between you view layer and your business logic. The controller accepts request, maps and validates your model, delegates requests to the correct business services, and finally decides which view to render based on the outcome of services called, of state of the model.
Everything is configured through xml, which gives you a single point where all your webflow logic and navigation is located (there is an eclipse plugin to visualize the navigation if you don’t like xml). Spring webflow also plays nice with other mvc controllers if you need to handle some requests the old fashioned way. And last but not least, spring webflow adds some scopes for your variables that are very handy. Besides request , session and application, you also get flow and conversation scope, which is kind of like session scope, but only for the current application window. That means you can have multiple windows/tabs in your browser without any of these interfering with each other.
But you should check it out for yourself, there is a small reference guide available on the spring website, as well as multiple demo’s in their svn repo. Also, the book “spring in action” touches the subject of webflow. Hope this is useful.
http://www.springsource.org/webflow

Accessing Spring Session scoped Proxy Beans

I'm developing a web-app using Struts 2 with a Spring 3 backend. I'm using Spring aop:proxy beans to handle my session beans rather than the Struts 2 SessionAware interface. Everything was working fine until I have an Action that is running under the Struts ExecAndWait interceptor. Because this interceptor in effect runs my action under a seperate thread, when I come to try and access my proxied session bean, I get a BeanCreationException/IllegalStateException. Is there another "spring way" that I can get hold of my session beans in this scenario?
Regards
From Execute and Wait Interceptor documentation
Important: Because the action will be running in a seperate thread, you can't use ActionContext because it is a ThreadLocal. This means if you need to access, for example, session data, you need to implement SessionAware rather than calling ActionContext.getSession().
The problem with session scoped-beans is that they depend on thread-local attributes set by RequestContextListener or RequestContextFilter. But the latter allows you to set very interesting threadContextInheritable flag...
If your ExecAndWait interceptor creates new thread per every request it serves, inheritable thread local should propagate session scoped beans to child threads. However if Struts uses thread pool (more likely, thou I haven't used Struts2 for ages) to serve this requests, this will have very unexpected and dangerous results. You might experiment with this flag, maybe it will do the trick.
You can Implement your own ExecAndWait interceptor using Spring. You can also delegate the management/creation of this action to Spring. For the later the details are in the S2 spring plugin documentation.
You can use ,RequestContextHolder(Holder class to expose the web request in the form of a thread-bound RequestAttributes object.) to make session scoped proxy beans available to child threads.
Define a custom ExecuteAndWait Interceptor and in doIntercept method use the following static method from RequestContextHolder
public static void setRequestAttributes(RequestAttributes attributes,boolean inheritable)
Bind the given RequestAttributes to the current thread.
Parameters:
attributes - the RequestAttributes to expose, or null to reset the thread-bound context
inheritable - whether to expose the RequestAttributes as inheritable for child threads (using an InheritableThreadLocal)
Sample Code
public class CustomExecuteAndWaitInterceptor extends ExecuteAndWaitInterceptor {
#Override
protected String doIntercept(ActionInvocation actionInvocation) throws Exception {
RequestAttributes requestAtteiAttributes = RequestContextHolder.getRequestAttributes(); //Return the RequestAttributes currently bound to the thread.
RequestContextHolder.setRequestAttributes(requestAtteiAttributes, true);
//do something else if you want ..
return super.doIntercept(actionInvocation);
}
}

How to get Hibernate session inside a Hibernate Interceptor?

How to get Hibernate session inside a Hibernate Interceptor?
I'm trying to use Hibernate to enforce data access by organization id transparently.
I have set a global Filter to filter all queries by organization id.
Now, I need to use an Entity interceptor to set Organizational Id on all Entities before Save/Update.
The organization id comes from HttpSession
I've set Organizational Id as a Filter property in Hibernate session which i want to retrieve inside my interceptor and use for all Inserts and Updates as well.
The problem is i dont seem to have access to Session inside the Interceptor. Any workarounds for this?
You can, but I would use a simple POJO just to keep things cleanly separated. Keep in mind that the value stored in the singleton will only be accessible by the same thread that handled the servlet request, so if you're doing any asynch, you will need to account for that. Here's a super basic impl:
public class OrgId {
public static ThreadLocal<Integer> orgId = new ThreadLocal<Integer>();
}
Since the Organizational Id is resident in the session, you could set the value of the ThreadLocal in an early servlet filter like this (not much error checking):
public class OrgIdFilter implements Filter {
public void doFilter(ServletRequest servletrequest, ServletResponse servletresponse, FilterChain filterchain) throws java.io.IOException, javax.servlet.ServletException {
int orgId = 0;
HttpServletRequest req = (HttpServletRequest) servletRequest;
HttpSession session = req.getSession();
orgId = Integer.parseInt(session.getAttribute("OrganizationalIdAttr"));
try {
OrgId.orgId.set(orgId);
filterChain.doFilter(servletRequest, servletresponse);
} finally {
OrgId.orgId.set(null); // Important to clear after request !!
}
}
}
This assumes that the orgId is in the session when the filter is called, but if not, you get the idea....
Then in your interceptor (or pretty much anywhere) you can get the thread's current orgId with:
OrgId.orgId.get(); // Might be null.....
A potential snafu here is that all these components (filter, OrgId and interceptor) need to be loaded by the same class loader to ensure that the OrgId class is effectively a singleton, otherwise, with multiple instances of the ThreadLocal hanging around it won't work consistently, or at all. Needless to say, all this needs to be happening in the same VM.
I am not sure if this is the cleanest way to solve this problem, but it does get you your orgId where you need it.
If all you need is the Organizational Id, you could put it in a static ThreadLocal and then access it in the interceptor.
On the other hand if you are dead set on getting the session, and this depends on what your environment is, you could ditch the interceptor and use an org.hibernate.event.FlushEntityEventListener which seems to be more along the lines of what you need anyways. You can get the session like this (rough pseudo code):
FlushEntityEventListener.onFlushEntity(FlushEntityEvent event)
EntityEvent entityEvent = event.getEntityEntry();
EntityPersister persister = entityEvent.getPersister();
SessionFactoryImplementor sessionFactoryImplor = persister.getFactory();
Session session = sessionFactoryImplor.getCurrentSession();
From the Hibernate 3 On Line Docs: The event system can be used in addition or as a replacement for interceptors.
When you create your Interceptor, if you can provide it with a reference to the SessionFactory, you can use SessionFactory#getCurrentSession
Interceptor can be made BeanFactoryAware and SessionFactory can be obtained using the bean factory from which current session can be obtained.
Since it seemed like a bad design because of the circular dependency and making the Interceptor aware of Spring container, i used ThreadLocal as suggested by Nicholas

Categories

Resources