Script sessions are created when /dwr/engine.js is included by a page. By default, the lifecycle is maintained by the org.directwebremoting.impl.DefaultScriptSessionManager.
If you call the following javascript function
dwr.engine.setNotifyServerOnPageUnload(true);
A remote DWR call will be made to the ScriptSessionManager when the page is unloaded, informing it to invalidate the script session. By default, ScriptSessions will be invalidated using a timeout strategy.
Non-dwr threads have no reference to the dwr-thread that created them. Because of this, WebContextFactory().get().getScriptSession() will return null in a non-dwr thread. You will therefore need to pass data from DWR threads to non-DWR threads such as the ScriptSession in the example below.
Most reverse ajax implementations require a separate thread to push data to clients. Spawning a separate thread for each DWR request is not scalable, instead you should use a single thread for reverse ajax.
Eg:
public class RemoteClass {
/**
* Remote DWR method called by a client to initiate the server push.
*/
public void startReverseAjax () {
ReverseAjaxThread thread = ReverseAjaxThread.getInstance();
thread.addScriptSession(WebContextFactory.get().getScriptSession());
}
}
public class ReverseAjaxThread {
private static ReverseAjaxThread INSTANCE;
private Set<ScriptSession> scriptSessions = new HashSet<ScriptSession>();
public synchronized ReverseAjaxThread getInstance() {
if (INSTANCE == null) {
INSTANCE = new ReverseAjaxThread();
INSTANCE.start();
}
return INSTANCE;
}
public void run() {
while (true) {
for (ScriptSession scriptSession : scriptSessions) {
if (scriptSession.isValid()) {
// alert('hello')
new ScriptProxy(scriptSession).addFunctionCall("alert", "hello");
} else {
synchronized (this) {
scriptSessions.remove(scriptSession);
}
}
}
Thread.sleep(10000); // sleep for 10 seconds
}
}
public synchronized void addScriptSession(ScriptSession scriptSession) {
// use a copy so that code reading from scriptSessions does not need to be synchronized
Set<ScriptSession> scriptSessionsCopy = new HashSet<ScriptSession>(scriptSessions);
scriptSessionsCopy.add(scriptSession);
scriptSessions = scriptSessionsCopy;
}
}
One of the most common ways to differentiate users on the same page is by setting attributes on the script session and getting them in a reverse ajax thread. Since the script session does not exist until engine.js is included this cannot be done in an MVC controller or a JSP, please vote for this issue http://bugs.directwebremoting.org/bugs/browse/DWR-320 to resolve this.
There are currently two best practices for populating the script session on page load.
1. Call a remote DWR method on page load which populates the script session:
public void remoteMethod() {
String value = "someValue"; // this may come from the HttpSession for example
ScriptSession scriptSession = WebContextFactory().get().getScriptSession();
scriptSession.setValue("key", value);
}
2. Add a script session listener which will be notified when script sessions are created and destroyed.
Container container = ServerContextFactory.get().getContainer();
ScriptSessionManager manager = container.getBean(ScriptSessionManager.class);
ScriptSessionListener listener = new ScriptSessionListener() {
public void sessionCreated(ScriptSessionEvent ev) {
HttpSession session = WebContextFactory.get().getHttpSession();
ScriptSession scriptSession = ev.getScriptSession();
String userId = (String) session.getAttribute("userId");
scriptSession.setAttribute("userId", userId);
}
public void sessionDestroyed(ScriptSessionEvent ev) {}
};
manager.addScriptSessionListener(listener);
Once the script session is populated, a reverse ajax thread can call scriptSession.getAttribute() to differentiate the users.
scriptSessionManager.getScriptSessionsByPage("/page?foo=bar")
If you would like to plug-in your own algorithm to determine the page name, you will need to implement your own org.directwebremoting.extend.PageNormalizer and plug it in using DWR's dependency injection mechanism in web.xml.
<servlet>
<servlet-name>dwr-invoker</servlet-name>
<display-name>DWR Servlet</display-name>
<description>Direct Web Remoter Servlet</description>
<servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
<init-param>
<param-name>org.directwebremoting.extend.PageNormalizer</param-name>
<param-value>foo.bar.MyPageNormalizer</param-value>
</init-param>
</servlet>
The script session manager can be obtained using the following code:
Container container = ServerContextFactory.get().getContainer(); ScriptSessionManager manager = container.getBean(ScriptSessionManager.class);