You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@myfaces.apache.org by Simon Kitching <sk...@apache.org> on 2008/10/02 16:39:36 UTC

Re: JSF: Multiple browser windows sharing Same session

simon.kitching@chello.at schrieb:
> Eelco Hillenius schrieb:
>>  
>>> Again, I don't see this as being particularly a JSF problem. I can't
>>> imagine that struts or wicket or rails would be able to deal with this
>>> problem any easier.
>>>     
>>
>> Actually, Wicket has an out-of-the-box solution for this. Wicket 
>> works with
>> 'page maps', which roughly represent the same thing as browser 
>> windows, and
>> we have some magic going for detecting new browser windows. It's a best
>> effort that works for most of the cases out there, but while we never 
>> get
>> complaints about it, there are probably a few corner cases that fall
>> through.
>>
>> For anyone interested, take a look at INewBrowserWindowListener and
>> WebPage#renderHead for the source code. Not the easiest code to follow
>> (after all, it's a bit of a nasty problem to solve), but it might 
>> give you
>> ideas on how to solve it for JSF.
>>
>> I saw someone else suggesting that keeping all your state on the client
>> would solve this. This is true, but it may open up a bunch of security
>> holes. Certainly when you assumed your state to be safe before. Also,
>> depending on 'how much' state is concerned, it might mean a considerable
>> efficiency hit. The most extreme example I've seen was an ASP.NET 
>> page with
>> over a megabyte of serialized state. That should be avoidable, but 
>> things
>> can add up quickly, so you should at least keep an eye on it.
>>   
>
> Thanks very much for the info! I will have a look at the Wicket 
> solution..

I have (finally) had a look at the wicket code, and it is indeed 
interesting. It's not a perfect solution, but is useful. Thanks for 
pointing it out, Eelco!

The core insight is that when open-in-new-tab is used, or a bookmark is 
activated, or a url is pasted into a window, the browser always creates 
a new javascript Window object. This object will have fresh values for 
the built-in properties (window.name etc) and will not have any custom 
javascript properties at all.

So *after* a page has been loaded by the new window, javascript in the 
page can check window.name or look for custom javascript properties to 
find out whether the window is a new one. If the page being rendered did 
not expect to be rendered into a new window then it can use javascript 
to set window.location to tell the server about it. In particular, it 
can ask the server to allocate a new "window context" and then render a 
new page (or the same page again).

When server processing of a request has triggered allocation of a new 
"window context", then it should simply render javascript into the page 
head that sets the appropriate window property (window.name or custom 
javascript property); it expects to be rendered into a "new" window. 
When server processing of a request has reused an existing "window 
context" then it should render script that checks for the magic state 
and redirects if the window is new. Typically the url redirected to 
tells the server to allocate a new "window context" then re-render the 
same page. The javascript to achieve this is pretty trivial.

There are the following issues:

(1) This approach does require javascript to be activated on the 
browser; when javascript is not activated then the new-window-detection 
simply has no effect.

(2) It only detects the problem *after* a request has been rendered on 
the server and streamed back to the browser. If the request has 
side-effects then the original window is now out-of-sync. However all of 
the use-cases (open-in-new-window, activate-bookmark, copy-paste-url) 
result in GET operations, and according to the principles of REST, no 
GET operation should affect server state.

Note in particular that for JSF server-side-state-saving a new 
view-state will have been pushed into the cache before the problem is 
detected. This state will never be used again (but is "newer" than the 
state for the original window).

(3) The new window may flicker a bit, as it shows the first page then 
immediately redirects. Or does putting the javascript check in the page 
head prevent this? I would guess that the bad page is present in the 
history anyway...

(4) It does require script to be rendered into every page (preferably 
into the head section). In most webapps that's not too hard to arrange, 
but a lib like Orchestra cannot automatically set that up.


Of course there is also the issue that simply *detecting* new windows is 
not enough; there needs to be some kind of per-window-storage too. 
Wicket takes care of that, and so can Orchestra. But Orchestra does not 
(yet) have an easy way to render the appropriate javascript checks.

Regards,
Simon


Re: JSF: Multiple browser windows sharing Same session

Posted by Scott O'Bryan <da...@gmail.com>.
I did a solution for JDEdwards a while back to handle multiple windows.  
You're mostly on base Simon.  There are a couple of things that could 
really take your flexibility to the next level though (if you have the 
stomach for it..  We did and it really paid off).

1. Don't tie the application scopes to a browser.  There should be the 
concept of a window (which handles the window by name) and then a 
concept of the active application within that window.  Posts to the 
server are made using the window, but then sent, essentially, to the 
application.
2. The special handling is confined to session scoped objects only.  If 
you can ensure that a request gets directed to the right view, 
request-scoped attributes are fine.  As should application scoped 
attributes.
3. Close window detection is extreemly helpful as well.  Modern browsers 
can know about a closed window 90% of the time.  This way you know what 
windows SHOULD be active and how many windows are open.  This might 
allow you to clean up the session early and whatnot.

In the system we had of JDEdwards (admittedly pre-JSF) we maintained a 
list of running applications off to the side of each browser window.  If 
the application was currently displayed in an active and open browser 
window, we brought it forward.  If it wasn't currently being displayed 
in the browser window, it brought it up over the current application 
while the other application remained running.  Furthermore, extending 
this into a portal type environment (where multiple apps can be actively 
displayed in the same window) was a snap as well.

Just some things to think about.

Scott

Simon Kitching wrote:
> simon.kitching@chello.at schrieb:
>> Eelco Hillenius schrieb:
>>>  
>>>> Again, I don't see this as being particularly a JSF problem. I can't
>>>> imagine that struts or wicket or rails would be able to deal with this
>>>> problem any easier.
>>>>     
>>>
>>> Actually, Wicket has an out-of-the-box solution for this. Wicket 
>>> works with
>>> 'page maps', which roughly represent the same thing as browser 
>>> windows, and
>>> we have some magic going for detecting new browser windows. It's a best
>>> effort that works for most of the cases out there, but while we 
>>> never get
>>> complaints about it, there are probably a few corner cases that fall
>>> through.
>>>
>>> For anyone interested, take a look at INewBrowserWindowListener and
>>> WebPage#renderHead for the source code. Not the easiest code to follow
>>> (after all, it's a bit of a nasty problem to solve), but it might 
>>> give you
>>> ideas on how to solve it for JSF.
>>>
>>> I saw someone else suggesting that keeping all your state on the client
>>> would solve this. This is true, but it may open up a bunch of security
>>> holes. Certainly when you assumed your state to be safe before. Also,
>>> depending on 'how much' state is concerned, it might mean a 
>>> considerable
>>> efficiency hit. The most extreme example I've seen was an ASP.NET 
>>> page with
>>> over a megabyte of serialized state. That should be avoidable, but 
>>> things
>>> can add up quickly, so you should at least keep an eye on it.
>>>   
>>
>> Thanks very much for the info! I will have a look at the Wicket 
>> solution..
>
> I have (finally) had a look at the wicket code, and it is indeed 
> interesting. It's not a perfect solution, but is useful. Thanks for 
> pointing it out, Eelco!
>
> The core insight is that when open-in-new-tab is used, or a bookmark 
> is activated, or a url is pasted into a window, the browser always 
> creates a new javascript Window object. This object will have fresh 
> values for the built-in properties (window.name etc) and will not have 
> any custom javascript properties at all.
>
> So *after* a page has been loaded by the new window, javascript in the 
> page can check window.name or look for custom javascript properties to 
> find out whether the window is a new one. If the page being rendered 
> did not expect to be rendered into a new window then it can use 
> javascript to set window.location to tell the server about it. In 
> particular, it can ask the server to allocate a new "window context" 
> and then render a new page (or the same page again).
>
> When server processing of a request has triggered allocation of a new 
> "window context", then it should simply render javascript into the 
> page head that sets the appropriate window property (window.name or 
> custom javascript property); it expects to be rendered into a "new" 
> window. When server processing of a request has reused an existing 
> "window context" then it should render script that checks for the 
> magic state and redirects if the window is new. Typically the url 
> redirected to tells the server to allocate a new "window context" then 
> re-render the same page. The javascript to achieve this is pretty 
> trivial.
>
> There are the following issues:
>
> (1) This approach does require javascript to be activated on the 
> browser; when javascript is not activated then the 
> new-window-detection simply has no effect.
>
> (2) It only detects the problem *after* a request has been rendered on 
> the server and streamed back to the browser. If the request has 
> side-effects then the original window is now out-of-sync. However all 
> of the use-cases (open-in-new-window, activate-bookmark, 
> copy-paste-url) result in GET operations, and according to the 
> principles of REST, no GET operation should affect server state.
>
> Note in particular that for JSF server-side-state-saving a new 
> view-state will have been pushed into the cache before the problem is 
> detected. This state will never be used again (but is "newer" than the 
> state for the original window).
>
> (3) The new window may flicker a bit, as it shows the first page then 
> immediately redirects. Or does putting the javascript check in the 
> page head prevent this? I would guess that the bad page is present in 
> the history anyway...
>
> (4) It does require script to be rendered into every page (preferably 
> into the head section). In most webapps that's not too hard to 
> arrange, but a lib like Orchestra cannot automatically set that up.
>
>
> Of course there is also the issue that simply *detecting* new windows 
> is not enough; there needs to be some kind of per-window-storage too. 
> Wicket takes care of that, and so can Orchestra. But Orchestra does 
> not (yet) have an easy way to render the appropriate javascript checks.
>
> Regards,
> Simon
>