Joerg Heinicke wrote:
Sylvain Wallez <sylvain <at> apache.org> writes:
I think I have found a more general problem with synchronization in Cocoon. I
tried to solve my problem with synchronization in flow script with an
intermediate object. This object handles the synchronized instantiation of my
component. Unfortunately I found out that "synchronized (session) { ... }"
still did not work - two requests of the same session run into that block at
the same time. I did some remote debugging. First I thought the reason is in
flow script as it also wraps the session, but it unwraps it later. The reason
is in HttpRequest class. Have a look at the code [1]:
As you can see on every request a new wrapper is instantiated which is really
bad. It is not possible to synchronize on Cocoon session objects.
Wow, very good point!
Or more simply we could store the wrapper in the session itself using an attribute. That way it would be guaranteed to be created only once.What we probably need is a Map mapping the server sessions to the wrapper objects.
Yes, that's another possibility I also had in mind. But on the one hand this smells a bit (storing a wrapper in the object that the wrapper wraps), on the other hand you can not restrict access to it, so it can be manipulated from somewhere else. But the Map solution can indeed be very resource consuming and a bottle neck.
I have implemented the session attribute solution. Would be nice if you can review it:
public Session getSession(boolean create) {
// we must assure a 1:1-mapping of server session to cocoon session
javax.servlet.http.HttpSession serverSession = this.req.getSession(create);
if (serverSession != null) {
synchronized (serverSession) {
// retrieve existing wrapper
this.session =
(HttpSession)serverSession.getAttribute(HTTP_SESSION);
if (this.session == null) {
// create wrapper
this.session = new HttpSession(serverSession);
serverSession.setAttribute(HTTP_SESSION, this.session);
}
}
} else {
// invalidate
this.session = null;
}
return this.session;
}
This approach has the problem of entering a synchronized block each time getSession is called. Although this may not that be much a problem in this particular case because it's unlikely that many parallel requests exist for a single request, we may totally avoid it except once. We also no more need to keep the wrapper as "this.session" as the servlet session stores the wrapper.
public Session getSession(boolean create) {
javax.servlet.http.HttpSession serverSession = this.req.getSession(create);
if (serverSession != null) {
Session session = (HttpSession)serverSession.getAttribute(HTTP_SESSION);
if (session = null) {
return createSessionWrapper(serverSession);
} else {
return session;
}
} else {
return null;
}
}
private Session createSessionWrapper(HttpSession serverSession) {
synchronized(serverSession) {
// recheck in the synchronized section
Session session = (HttpSession)serverSession.getAttribute(HTTP_SESSION);
if (session = null) {
session = new HttpSession(serverSession);
serverSession.setAttribute(HTTP_SESSION, session);
}
return session;
}
}
An "update wrapper" (which was indeed an "update wrapped session") as in the old implementation is IMO no longer necessary as only the server session holds the wrapper - if it is a new server session we also must provide a new wrapper.
To avoid or at least recognize manipulation of the session attribute it is maybe
possible to let Cocoon's HttpSession implement HttpSessionAttributeListener and
to check on attributeReplaced(HttpSessionBindingEvent) [1] whether the wrapper
was replaced and not just removed on invalidation of the session. But first this
is no 100%-solution as someone could first remove and later set the attribute
and second it is again overhead (the event is triggered on every session
attribute add/remove/replace).
AFAICS the HTTPSessionBindingListener [2] does not help as there is no type of
HttpSessionBindingEvent, just the information that the wrapper was removed - and
this must happen when the session is invalidated.
Sorry, what problem are you trying to solve with having the wrapper being notified of updates?
Sylvain
-- Sylvain Wallez Anyware Technologies http://apache.org/~sylvain http://anyware-tech.com Apache Software Foundation Member Research & Technology Director
