PDA

View Full Version : HessianServlet with Session Scoped dependencies


swiegersf
06-30-2010, 02:52 PM
Good day,

I am trying to communicate to my CDI bootstrapped JavaEE application via Hessian. The problem I have is that each client invocation of the Hessian servlet seems to be done in a new CDI session.

My Hessian servlet:


public class WebServiceRemoteInvocationHandler extends HessianServlet implements
RemoteInvocationHandler {

private static final long serialVersionUID = 1L;

@Inject
private ServerState serverState;

@Override
public RemoteInvocationResult invoke(RemoteInvocationCommand cmd) {
System.out.println(serverState.toString()); //should be same on every call from the same client
}

}


my ServerState implementation:


@SessionScoped
public class SessionMapServerState implements ServerState, Serializable {

private static final long serialVersionUID = 1L;

}


and my client (which runs as a normal Java SE process using a SE bootstrapped CDI container like Weld or ResinContainer):


public class AppStart {

@Produces
@ApplicationScoped
public RemoteInvocationHandler getRemoteInvocationHandler()
throws Exception {
HessianProxyFactory factory = new HessianProxyFactory();
RemoteInvocationHandler remote = (RemoteInvocationHandler) factory
.create(RemoteInvocationHandler.class,
"http://localhost:8080/alchemy-no-test-app-web/remoteInvocation");
return remote;
}
}


How can I enable the use of sessions from my SE application? I assume there must be some way to create and destroy a client session similar to what HttpClient does, but alas my knowledge of Hessian is a bit limited.

ferg
07-01-2010, 12:26 AM
I've added a bug report for this.

Hessian is designed to be stateless, so technically sessions don't make sense. But since it's a feature that's been asked for before, I'll add a bug report for it.

swiegersf
07-01-2010, 07:46 AM
Thanks Scott, I managed to get it to work by simply enabling cookie management via the java.net.CookieHandler.

swiegersf
07-05-2010, 11:48 AM
Alas, it seems as if this issue is still haunting me!

So using the above approach (Hessian servlet together with cookie management on the client) I have managed to get Resin to correctly use a session scoped Map that "survives" multiple client requests.

However, I was doing some testing and noticed that objects that I stored in my SessionScoped server side Map never gets garbage collected, even though the session properly times out. Increasing the log level of my server, I notice that whenever the hessian servlet session times out, I get the following error on my console:


[13:32:54.993] {resin-32} SessionImpl[aaaKevsSpi-4I5cyExIMs,/alchemy-no-test-app-web] timeout
[13:32:54.993] {resin-32} SessionImpl[aaaKevsSpi-4I5cyExIMs,/alchemy-no-test-app-web] remove
[13:32:54.993] {resin-32} javax.enterprise.context.ContextNotActiveException : com.caucho.server.webbeans.SessionScope cannot be used because it's not currently active
at com.caucho.config.scope.AbstractScopeContext.get(A bstractScopeContext.java:91)
at com.caucho.config.inject.InjectManager$NormalInsta nceReferenceFactory.create(InjectManager.java:4251 )
at com.caucho.config.inject.InjectManager$ReferenceFa ctory.create(InjectManager.java:4010)
at alchemy.remote.server.impl.SessionMapServerState__ ResinScopeProxy.destroy(Unknown Source)
at alchemy.no.session.context.rwt.AlchemySessionListe ner.sessionDestroyed(AlchemySessionListener.java:4 0)
at com.caucho.server.session.SessionImpl.notifyDestro y(SessionImpl.java:1018)
at com.caucho.server.session.SessionImpl.removeEvent( SessionImpl.java:995)
at com.caucho.util.LruCache.remove(LruCache.java:613)
at com.caucho.server.session.SessionManager.removeSes sion(SessionManager.java:1581)
at com.caucho.server.session.SessionImpl.invalidate(S essionImpl.java:1090)
at com.caucho.server.session.SessionImpl.invalidateTi meout(SessionImpl.java:1045)
at com.caucho.server.session.SessionImpl.timeout(Sess ionImpl.java:951)
at com.caucho.server.session.SessionManager.handleAla rm(SessionManager.java:1665)
at com.caucho.util.Alarm.handleAlarm(Alarm.java:453)
at com.caucho.util.Alarm.run(Alarm.java:425)
at com.caucho.util.ThreadPool$PoolThread.runTasks(Thr eadPool.java:901)
at com.caucho.util.ThreadPool$PoolThread.run(ThreadPo ol.java:866)



I fear this exception might be preventing Candi from properly cleaning up the session state, and hence my server side objects never gets released.

swiegersf
07-05-2010, 12:00 PM
Ah, upon further inspection, I must add that I have a servlet listener registered on my application:


public class AlchemySessionListener implements HttpSessionListener,
ServletRequestListener {

@Inject
private ServerState serverState;

@Inject
private Logger log;

@Override
public void sessionCreated(HttpSessionEvent ev) {
}

@Override
public void sessionDestroyed(HttpSessionEvent ev) {
serverState.destroy();
}

...


The problem seems to be that the CDI session is closed before the servlet listener's sessionDestroyed(..) method is invoked.

According to the CDI spec (section 6.7.2):


The session context is shared between all servlet requests that occur in the same HTTP session. The session context is destroyed
when the HTTPSession times out, after all HttpSessionListeners have been called

swiegersf
07-06-2010, 05:38 AM
Oh dear, more trouble. It seems as if the approach using java.net's cookies only goes that far - HessianServlet seems to take liberties with the servlet context, which sometimes results in the wrong session being returned when I have multiple clients connected at the same time.

Is it a fool's errand to use session scope with Hessian at this stage, or am I simply doing something wrong? If my client uses the JSESSIONID cookie as per the servlet spec, should HessianServlet not bootstrap the CDI session correctly for each client, or is there some dark magic happening inside HessianServlet that causes Resin to inject the wrong session's bean into the active session?

ferg
07-06-2010, 07:58 PM
Well, the CDI listener issue looks like a Resin bug (the session close is currently implemented by a listener as well.)

For the other issues, Hessian doesn't directly support sessions/cookies at the moment, so it's possible the tweak you're using is running into some other issues.

swiegersf
07-07-2010, 07:32 AM
Thanks Scott,

I found the reason for the problem of the wrong scope being loaded - it was my test that was broken, not HessianServlet or anything in Resin. When using a CookieHandler, the HessianServlet correctly loads the correct the scope as per the servlet spec.

Cheers
Francois