DWR

Create script session before including engine.js

Details

  • Type: New Feature New Feature
  • Status: In Progress In Progress
  • Priority: Normal Normal
  • Resolution: Unresolved
  • Affects Version/s: None
  • Fix Version/s: 3.0.1
  • Component/s: None
  • Description:
    Hide
    I would like to populate the script session in my controller code which executes before engine.js is included and hence before a script session exists for the page that I am about to render.

    A solution to this problem could be
    1. A javax.servlet.Filter that creates the script session and manages the dwr thread local.
    ie WebContextBuilder.engageThread() and WebContextBuilder.disengageThread()

    2. A jsp tag which sets the javascript variable dwr.engine._scriptSessionId based on the thread local then includes engine.js.
    This tag might throw an exception if the thread local is not set.

    3. Engine.js is tweaked slightly so that it only creates a script session if dwr.engine._scriptSessionId is not defined.

    This gives rise to a couple more JSP tag opportunities
    4. Tags to get and set from scope="script" (similar to jstl's set and get tags)

    5. A scriptSession tag which wraps the page, this would manage the thread local and could be used instead of the javax.servlet.Filter mentioned in point 1. If this tag is used instead of the filter, the controller would not be able to populate the script session.
    Show
    I would like to populate the script session in my controller code which executes before engine.js is included and hence before a script session exists for the page that I am about to render. A solution to this problem could be 1. A javax.servlet.Filter that creates the script session and manages the dwr thread local. ie WebContextBuilder.engageThread() and WebContextBuilder.disengageThread() 2. A jsp tag which sets the javascript variable dwr.engine._scriptSessionId based on the thread local then includes engine.js. This tag might throw an exception if the thread local is not set. 3. Engine.js is tweaked slightly so that it only creates a script session if dwr.engine._scriptSessionId is not defined. This gives rise to a couple more JSP tag opportunities 4. Tags to get and set from scope="script" (similar to jstl's set and get tags) 5. A scriptSession tag which wraps the page, this would manage the thread local and could be used instead of the javax.servlet.Filter mentioned in point 1. If this tag is used instead of the filter, the controller would not be able to populate the script session.

Issue Links

Activity

Hide
Lance Semmens added a comment - 10/Dec/08 11:16 AM

Here's what the tags might look like

<!-- creates a script session and calls WebContextBuilder.engageThread() -->
<dwr:script-session>

<html>
<head>
<!-- sets dwr.engine._scriptSessionId and includes engiune.js -->
<dwr:engine-js />
</head>
<body>
<!-- sets the userType script session attribute, this can now be used by a reverse ajax thread -->
<dwr:script-session-set var="userType" value="restricted" />

<!-- copies from the script session to a page scoped attribute -->
<dwr:script-session-copy fromVar="userType" toVar="pageUserType" toScope="page" />

<!-- page scoped attribute can be used by jstl etc -->
<c:out value="${pageUserType}" />
</body>
</html>

<!-- WebContextBuilder.disengageThread() -->
</dwr:script-session>

Show
Lance Semmens added a comment - 10/Dec/08 11:16 AM Here's what the tags might look like <!-- creates a script session and calls WebContextBuilder.engageThread() --> <dwr:script-session> <html> <head> <!-- sets dwr.engine._scriptSessionId and includes engiune.js --> <dwr:engine-js /> </head> <body> <!-- sets the userType script session attribute, this can now be used by a reverse ajax thread --> <dwr:script-session-set var="userType" value="restricted" /> <!-- copies from the script session to a page scoped attribute --> <dwr:script-session-copy fromVar="userType" toVar="pageUserType" toScope="page" /> <!-- page scoped attribute can be used by jstl etc --> <c:out value="${pageUserType}" /> </body> </html> <!-- WebContextBuilder.disengageThread() --> </dwr:script-session>
Hide
Mike Wilson added a comment - 10/Jul/09 10:06 AM

In DWR-364, and in the "File upload porgress" mailing list thread, we have started to look at switching to client-side generation of scriptSessionId. We would need to make sure this is compatible with the JSP tag stuff in this ticket.
Just so I get this right: this ticket is both about inserting the appropriate scriptSessionId in the page response AND to prepopulate data in the corresponding scriptSession on the server-side? (If it had only been about the former, to save an "extra" scriptSessionId request, then it would be solved completely with client-side generated scriptSessionId)

Show
Mike Wilson added a comment - 10/Jul/09 10:06 AM In DWR-364, and in the "File upload porgress" mailing list thread, we have started to look at switching to client-side generation of scriptSessionId. We would need to make sure this is compatible with the JSP tag stuff in this ticket. Just so I get this right: this ticket is both about inserting the appropriate scriptSessionId in the page response AND to prepopulate data in the corresponding scriptSession on the server-side? (If it had only been about the former, to save an "extra" scriptSessionId request, then it would be solved completely with client-side generated scriptSessionId)
Hide
Lance Semmens added a comment - 10/Jul/09 10:32 AM

This issue is mainly about having access to the scriptSession in the controller (MVC) prior to rendering the view. Currently this can only be done using with a remote call on page load.

Show
Lance Semmens added a comment - 10/Jul/09 10:32 AM This issue is mainly about having access to the scriptSession in the controller (MVC) prior to rendering the view. Currently this can only be done using with a remote call on page load.
Hide
Mike Wilson added a comment - 05/Feb/11 12:11 PM

Hi Lance, sorry for the time passing on this one, but the new client-side scriptSessionId algorithm is now in place and I have started to think about how to make the use-case in this ticket to work. I have some ideas but it would be great if you could create a simple project showing how you imagine the application code for this feature. Or even make a failing test case for testdwr. Having that will make it much easier to get this right!

Show
Mike Wilson added a comment - 05/Feb/11 12:11 PM Hi Lance, sorry for the time passing on this one, but the new client-side scriptSessionId algorithm is now in place and I have started to think about how to make the use-case in this ticket to work. I have some ideas but it would be great if you could create a simple project showing how you imagine the application code for this feature. Or even make a failing test case for testdwr. Having that will make it much easier to get this right!
Hide
Lance Semmens added a comment - 06/Feb/11 10:47 AM

Hi Mike,

Think of a chat application with many different chat rooms, each for a different topic. The user selects a the java topic and is redirected to the page
www.chat.com/chatroom?topic=java

Now, we want to send this user all of the messages for the "java" topic using reverse ajax. Currently this can be done a couple of ways:

1. The serverside push uses scriptSessionManager.getScriptSessionsByPage("chatroom?topic=java");

OR

2. Call a remote method on page load which invokes scriptSession.setAttribute("topic", "java"). The serverside push can then use this attribute to determine the topic for each client.

I prefer option 2 as I think option 1 is a bit hacky. Option 2 does a remote method invocation which I think is unnecessary, I think this could be done in the Action class (MVC).

So, the solution would be something like
1. In the Action class (MVC), a call is made to getScriptSession(). This method needs to be tweaked to lazy init a script session if one does not exist for the current thread.
2. The action makes a call to scriptSession.setAttribute("topic", request.getParameter("topic"))
3. In the jsp, engine.js is included but an extra piece of javascript initiates the scriptsession id. This could be done in a <enginejs /> tag or similar.

My initial JIRA mentioned using a filter to create the script session. I think I prefer the lazy init option discussed in point 1.

Hope this clears things up

Show
Lance Semmens added a comment - 06/Feb/11 10:47 AM Hi Mike, Think of a chat application with many different chat rooms, each for a different topic. The user selects a the java topic and is redirected to the page www.chat.com/chatroom?topic=java Now, we want to send this user all of the messages for the "java" topic using reverse ajax. Currently this can be done a couple of ways: 1. The serverside push uses scriptSessionManager.getScriptSessionsByPage("chatroom?topic=java"); OR 2. Call a remote method on page load which invokes scriptSession.setAttribute("topic", "java"). The serverside push can then use this attribute to determine the topic for each client. I prefer option 2 as I think option 1 is a bit hacky. Option 2 does a remote method invocation which I think is unnecessary, I think this could be done in the Action class (MVC). So, the solution would be something like 1. In the Action class (MVC), a call is made to getScriptSession(). This method needs to be tweaked to lazy init a script session if one does not exist for the current thread. 2. The action makes a call to scriptSession.setAttribute("topic", request.getParameter("topic")) 3. In the jsp, engine.js is included but an extra piece of javascript initiates the scriptsession id. This could be done in a <enginejs /> tag or similar. My initial JIRA mentioned using a filter to create the script session. I think I prefer the lazy init option discussed in point 1. Hope this clears things up
Hide
Lance Semmens added a comment - 06/Feb/11 10:57 AM

I've had a bit more of a think about this and perhaps a servlet filter is required. From memory the dwr servlet calls engageThread() and disengageThread() to set the DWR thread local(s). I think the filter will need to do the same. The lazy init approach will fall over in a servlet container that re-uses a pool of threads which I assume is all servlet containers.

Show
Lance Semmens added a comment - 06/Feb/11 10:57 AM I've had a bit more of a think about this and perhaps a servlet filter is required. From memory the dwr servlet calls engageThread() and disengageThread() to set the DWR thread local(s). I think the filter will need to do the same. The lazy init approach will fall over in a servlet container that re-uses a pool of threads which I assume is all servlet containers.
Hide
Mike Wilson added a comment - 07/Feb/11 2:20 PM

Comments in order of execution

Servlet filter to set up DWR ThreadLocals:
Aren't you aiming to do all work in the "page" request, ie the root request loading the page? Then no extra DWR info is added to the request, so we can't set up our ThreadLocals. We can only do this for requests sent by the DWR client layer.

Reuse existing ScriptSession if exists:
As we don't have the extra DWR info (the page request doesn't transfer any scriptSessionId), we don't know if there is already a ScriptSession. On the flip side though, if you are using the default ScriptSession model, where a new ScriptSession is created for every page load, then you can be certain that no ScriptSession exists yet and can safely create a new one.

Creating a new ScriptSession:
I guess this could be done like this with the current APIs and without requiring being inside a DWR thread:
Container container = ServerContextFactory.get().getContainer();
ScriptSessionManager ssmgr = container.getBean(ScriptSessionManager.class);
String myScriptSessionId = ...
ScriptSession ss = ssmgr.getScriptSession(myScriptSessionId, page, sessionId);

Handing over the scriptSessionId to DWR engine.js in the page:
If my assumptions above are correct, this is the only part left that needs implementing. You need some way of setting the scriptSessionId before engine.js gets a chance to set up its own, is that right?

Show
Mike Wilson added a comment - 07/Feb/11 2:20 PM Comments in order of execution Servlet filter to set up DWR ThreadLocals: Aren't you aiming to do all work in the "page" request, ie the root request loading the page? Then no extra DWR info is added to the request, so we can't set up our ThreadLocals. We can only do this for requests sent by the DWR client layer. Reuse existing ScriptSession if exists: As we don't have the extra DWR info (the page request doesn't transfer any scriptSessionId), we don't know if there is already a ScriptSession. On the flip side though, if you are using the default ScriptSession model, where a new ScriptSession is created for every page load, then you can be certain that no ScriptSession exists yet and can safely create a new one. Creating a new ScriptSession: I guess this could be done like this with the current APIs and without requiring being inside a DWR thread: Container container = ServerContextFactory.get().getContainer(); ScriptSessionManager ssmgr = container.getBean(ScriptSessionManager.class); String myScriptSessionId = ... ScriptSession ss = ssmgr.getScriptSession(myScriptSessionId, page, sessionId); Handing over the scriptSessionId to DWR engine.js in the page: If my assumptions above are correct, this is the only part left that needs implementing. You need some way of setting the scriptSessionId before engine.js gets a chance to set up its own, is that right?
Hide
Lance Semmens added a comment - 07/Feb/11 2:43 PM

> Servlet filter to set up DWR ThreadLocals:
> Aren't you aiming to do all work in the "page" request, ie the root request loading the page? Then no extra DWR info is added to the request, so we can't set up our ThreadLocals. We can only do this for requests sent by the DWR client layer.

You are correct that currently DWR has no interaction with the PAGE request. What I am proposing is that a subset of PAGE requests are mapped to the filter and do have DWR thread locals associated with them.

> Reuse existing ScriptSession if exists:
> As we don't have the extra DWR info (the page request doesn't transfer any scriptSessionId), we don't know if there is already a ScriptSession. On the flip side though, if you are using the default ScriptSession model, where a new ScriptSession is created for every page load, then you can be certain that no ScriptSession exists yet and can safely create a new one.

For PAGE requests, the scriptSession will NEVER exist. A scriptSession currently is created when engine.js is included which is after the PAGE request. I am proposing that we could instead do this step a bit earlier in the PAGE request. Currently, when engine.js is included, a scriptSessionId is not passed. engine.js fires off a request to create the scriptSession (and scriptSessionId). Only subsequent DWR requests pass the scriptSessionId.

> Creating a new ScriptSession:
> I guess this could be done like this with the current APIs and without requiring being inside a DWR thread:>
> Container container = ServerContextFactory.get().getContainer();
> ScriptSessionManager ssmgr = container.getBean(ScriptSessionManager.class);
> String myScriptSessionId = ...
> ScriptSession ss = ssmgr.getScriptSession(myScriptSessionId, page, sessionId);

I was thinking that for PAGE requests mapped to the filter, it could be done as if it was a normal DWR request.
eg WebContextFactory.get().getScriptSession()

> Handing over the scriptSessionId to DWR engine.js in the page:
> If my assumptions above are correct, this is the only part left that needs implementing. You need some way of setting the scriptSessionId before engine.js gets a chance to set up its own, is that right?

Yes, the JSP tag (or whatever) would call dwr.engine.setScriptSessionId() with the thread local script session id. The javascript would then not send off a serverside request to create a scriptSessionId.

Show
Lance Semmens added a comment - 07/Feb/11 2:43 PM > Servlet filter to set up DWR ThreadLocals: > Aren't you aiming to do all work in the "page" request, ie the root request loading the page? Then no extra DWR info is added to the request, so we can't set up our ThreadLocals. We can only do this for requests sent by the DWR client layer. You are correct that currently DWR has no interaction with the PAGE request. What I am proposing is that a subset of PAGE requests are mapped to the filter and do have DWR thread locals associated with them. > Reuse existing ScriptSession if exists: > As we don't have the extra DWR info (the page request doesn't transfer any scriptSessionId), we don't know if there is already a ScriptSession. On the flip side though, if you are using the default ScriptSession model, where a new ScriptSession is created for every page load, then you can be certain that no ScriptSession exists yet and can safely create a new one. For PAGE requests, the scriptSession will NEVER exist. A scriptSession currently is created when engine.js is included which is after the PAGE request. I am proposing that we could instead do this step a bit earlier in the PAGE request. Currently, when engine.js is included, a scriptSessionId is not passed. engine.js fires off a request to create the scriptSession (and scriptSessionId). Only subsequent DWR requests pass the scriptSessionId. > Creating a new ScriptSession: > I guess this could be done like this with the current APIs and without requiring being inside a DWR thread:> > Container container = ServerContextFactory.get().getContainer(); > ScriptSessionManager ssmgr = container.getBean(ScriptSessionManager.class); > String myScriptSessionId = ... > ScriptSession ss = ssmgr.getScriptSession(myScriptSessionId, page, sessionId); I was thinking that for PAGE requests mapped to the filter, it could be done as if it was a normal DWR request. eg WebContextFactory.get().getScriptSession() > Handing over the scriptSessionId to DWR engine.js in the page: > If my assumptions above are correct, this is the only part left that needs implementing. You need some way of setting the scriptSessionId before engine.js gets a chance to set up its own, is that right? Yes, the JSP tag (or whatever) would call dwr.engine.setScriptSessionId() with the thread local script session id. The javascript would then not send off a serverside request to create a scriptSessionId.
Hide
Mike Wilson added a comment - 08/Feb/11 3:09 PM

I should mention that the scriptSessionId algorithm has changed since you submitted this ticket, see DWR-26, and most of the time there is no extra request to get the scriptSessionId as it is generated in the browser. Well not entirely in the browser as half of the scriptSessionId is generated once by the server and shared by all windows from the same browser process. This last thing actually causes problems when wanting to both assign the scriptSessionId and pre-create the ScriptSession on the server, as we need to enforce that the first half of the scriptSessionId is shared by all pages in the same browser process (or otherwise need to extend the protocol to rename ScriptSessions on the fly when discovering conflicts).

So I wonder if your goal is already met as the extra scriptSessionId request is gone, or if not, whether a solution would work for you where you can assign scriptSessionId on the server on all but the first DWR page call (as the tricky thing is to do this before the shared part of the id has been established) ?

Show
Mike Wilson added a comment - 08/Feb/11 3:09 PM I should mention that the scriptSessionId algorithm has changed since you submitted this ticket, see DWR-26, and most of the time there is no extra request to get the scriptSessionId as it is generated in the browser. Well not entirely in the browser as half of the scriptSessionId is generated once by the server and shared by all windows from the same browser process. This last thing actually causes problems when wanting to both assign the scriptSessionId and pre-create the ScriptSession on the server, as we need to enforce that the first half of the scriptSessionId is shared by all pages in the same browser process (or otherwise need to extend the protocol to rename ScriptSessions on the fly when discovering conflicts). So I wonder if your goal is already met as the extra scriptSessionId request is gone, or if not, whether a solution would work for you where you can assign scriptSessionId on the server on all but the first DWR page call (as the tricky thing is to do this before the shared part of the id has been established) ?

People

Dates

  • Created:
    10/Dec/08 10:51 AM
    Updated:
    25/May/11 8:58 PM