File APIs for Java Developers
Manipulate DOC, XLS, PPT, PDF and many others from your application.
http://aspose.com/file-tools
The moose likes Struts and the fly likes Struts2 ModelDriven Not Threadsafe? Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Frameworks » Struts
Bookmark "Struts2 ModelDriven Not Threadsafe?" Watch "Struts2 ModelDriven Not Threadsafe?" New topic
Author

Struts2 ModelDriven Not Threadsafe?

Ron Zavner
Greenhorn

Joined: Nov 28, 2010
Posts: 20
Hello,

I'm working with struts2, hibernate and spring and using model driven pattern. It seems that there is a serious issue when trying to fetch an object with 2 different users and sessions (also different computers) at the same time exactly.

More info...
Let's say we have a Project object which has 2 members - user and name.
Both users will try to fetch their Project object (which is a different object for different user of course). So User A would have a project with id 498 and User B would have a project with ID 499.

The struts action would recognize that they're trying to fetch an object with different ID but it seems that both of the users have the same Project object instance and therefore they see the same result.
You could see in the log provided here:


2011-12-08 14:07:21 LoginInterceptor [INFO] User 17 is invoking populateProject, params: id=499
2011-12-08 14:07:21 LoginInterceptor [INFO] User 4 is invoking populateProject, params: id=498
2011-12-08 14:07:21 ProjectAction [INFO] Obj: hbn.Project@e2df60d, Session User Id is 17, obj.user.id is 4
2011-12-08 14:07:21 ProjectAction [INFO] Obj: hbn.Project@e2df60d, Session User Id is 4, obj.user.id is 4

How could I solve it?

Thanks,
Ron.
Mohana Rao Sv
Ranch Hand

Joined: Aug 01, 2007
Posts: 485

Post your code how you implemented it.


ocjp 6 — Feeding a person with food is a great thing in this world. Feeding the same person by transferring the knowledge is far more better thing. The reason is the amount of satisfaction which we get through food is of only one minute or two. But the satisfaction which we can get through the knowledge is of life long.
Ron Zavner
Greenhorn

Joined: Nov 28, 2010
Posts: 20
Hi,

This is the getter:

public Project getObj() {
logger.info("Obj: " + obj + ", Session User Id is " + getUser().getId() + ", obj.user.id is " + obj.getUser().getId());
return obj;
}

The fetching part is doing some business logic but the main part would be:
obj = dao.read(isLazy, allCrits);

Where obj is defined as a data member of the action with the type of the ModelDriven.
Joe Ess
Bartender

Joined: Oct 29, 2001
Posts: 8964
    
    9

You haven't given us much to work on. Have a look at this article from our FAQ on how to describe a problem. The better question you ask, the more help we can be.


[How To Ask Questions On JavaRanch]
Ron Zavner
Greenhorn

Joined: Nov 28, 2010
Posts: 20
Hi

Sorry bout that, will try to be more clear.

This is how the action starts:

public class ProjectAction extends GenericAction<Project> implements ModelDriven<Project> {

@Autowired
private WebsiteDAO websiteDAO;

@Autowired
private ProjectManagerDAO projectManagerDAO;

private Project obj;

public String populate() throws DataAccessException {
String myId = getRequest().getParameter("id");
if (myId != null && !myId.equals("")) {
logger.info("Fetching Project with Id " + id + " of user " + getUser().getId());
obj = (Project) dao.read(Integer.parseInt(myId));
logger.info("After fetch Obj: " + obj + ", Session User Id is " + getUser().getId() + ", obj.user.id is " + obj.getUser().getId());
}
return "form";
}

public Project getObj() {
logger.info("In getObj() Obj: " + obj + ", Session User Id is " + getUser().getId() + ", obj.user.id is " + obj.getUser().getId());
return obj;
}
....
}

In the UI I call populateProject?id=... from 2 different sessions at the same time and then the correct object is being fetched. Then in the jsp there is a form which has the follwoing line
<s:textfield name="name" key="Name" size="30" value="%{obj.name}"/>

This line is probably call the getObj function which for some reason access the same obj instance (for the different users).

That's the log file:

As you can see - the correct object was fetched and also saved to different obj instance. Problem started in the getObj method - last 2 lines of log.

2011-12-08 15:17:48 ProjectAction [INFO] Fetching Project with Id 498 of user 4
2011-12-08 15:17:48 ProjectAction [INFO] Fetching Project with Id 499 of user 17
2011-12-08 15:17:48 ProjectAction [INFO] After fetch Obj: hbn.Project@6c461f7c, Session User Id is 4, obj.user.id is 4
2011-12-08 15:17:48 ProjectAction [INFO] After fetch Obj: hbn.Project@3fa419d, Session User Id is 17, obj.user.id is 17
2011-12-08 15:17:48 ProjectAction [INFO] In getObj() Obj: hbn.Project@3fa419d, Session User Id is 17, obj.user.id is 17
2011-12-08 15:17:48 ProjectAction [INFO] In getObj() Obj: hbn.Project@3fa419d, Session User Id is 4, obj.user.id is 17

Thanks a lot.
Joe Ess
Bartender

Joined: Oct 29, 2001
Posts: 8964
    
    9

A Struts 2 Action instance is created for every request and do not need to be thread-safe. Conversely, Interceptors are shared between requests and must be thread-safe.

Struts 2 Guide: Writing Interceptors
Ron Zavner
Greenhorn

Joined: Nov 28, 2010
Posts: 20
I know...but as you can see the getObj method is part of the function so has to be thread-safe...but you can see from the code and log the obj was not thread safe so the problem still remains...
Joe Ess
Bartender

Joined: Oct 29, 2001
Posts: 8964
    
    9

You cannot use instance-scope variables like the way you have obj declared in thread-safe code.
Ron Zavner
Greenhorn

Joined: Nov 28, 2010
Posts: 20
So how should I use it?
In the tutorials of Model Driven I've seen that they declare the object as a data member of the action...it's exactly what i did.
Joe Ess
Bartender

Joined: Oct 29, 2001
Posts: 8964
    
    9

I'm sorry. I got confused and thought you were writing an interceptor. The interceptor has to be thread safe. The action does not, so the code you posted looks fine.
Are you certain that the code you posted is the code you are running? If you declared obj to be static, you'd see the behavior you are witnessing.
Ron Zavner
Greenhorn

Joined: Nov 28, 2010
Posts: 20
Yes I'm sure, I re wrote the code (and tested it) so i could post something that would be clear

Maybe it has to do with struts-spring plugin? Since spring is initiating the struts actions...

Spring conf:
<bean id="projectAction" class="actions.ProjectAction">
<property name="dao" ref="projectDAO" />
</bean>
<bean id="projectDAO" class="hbn.dao.ProjectDAO">
<property name="sessionFactory" ref="sessionFactory" />
</bean>

Struts.xml

<action name="*Project" method="{1}" class="projectAction">
<result name="form">jsp/Project/form.jsp</result>
<result name="list">jsp/Project/list.jsp</result>
<result name="details">jsp/Project/details.jsp</result>
<result name="showReport">jsp/Project/showReport.jsp</result>
</action>

Thanks.

Ron Zavner
Greenhorn

Joined: Nov 28, 2010
Posts: 20
The problem is solved.

The issue was indeed due to struts and spring integration - the scope wasn't defined so default scope singelton was used.
After changing the action definition to the following it's working great

<bean id="projectAction" class="actions.ProjectAction" scope="prototype">
<property name="dao" ref="projectDAO" />
</bean>

Thanks.
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: Struts2 ModelDriven Not Threadsafe?