Support for multiple browser tabs - solution

I’ve trying to solve that Vaadin problem with multiple browser tabs. Currently only solution is to override Application#getWindow() and create additional main windows. That doesn’t solve the real problem, which is that all tabs share the same application class instance when they should have separate instances.

It seems that real source of these problems is that web browser uses same http session for all browser tabs that are using same target URL. Vaadin seems to link application instances to http session. If the session is same for all tabs, then there is only one instance of your application class.

I think I may have now somewhat better solution. It’s not perfect, but my tests doesn’t give any out-of-sync errors and each tab has completely separate set of windows.

I don’t know how to force web browser to use different http sessions for tabs. Does anybody know? If there is a way, then much simpler and better solution could be created. Although I cannot force new http sessions, I can make Vaadin to create separate instances of my application class for each browser tab. Vaadin doesn’t create separate application instances if both http session and the application URL are same. If session cannot be changed, then let’s change the URL.

So first step is to generate different URLs for browser tabs. Normally your URL is like “www.fobar.com/testapp”. Let’s changed it so that there is variable part like “www.foobar.com/testapp/session12345” which is different for tabs. This can be done by extending com.vaadin.terminal.gwt.server.ApplicationServlet or com.vaadin.terminal.gwt.server.AbstractApplicationServlet. Anyway, you need to override javax.servlet.http.HttpServlet#service() method so that you can get requests before Vaadin gets them. Test if the URL contains that “sessionNNNN” part. If it doesn’t, create new URL which has it and make that part unique for example by using current time in milliseconds or some random number. Now use HttpServletResponse#redirect(), which forces web browser to resend request with your new URL. You need to check if URL’s path info starts with “/UIDL/” or with “/VAADIN/”, you must not redirect. That’s because those paths must be located right under your original servlet path. Does anybody know if there are other special prefixes?

Now we have unique URL for each browser tab. That’s not enough. Because we have kind of changed servlet path, we have to use request wrapper to change how Vaadin sees some aspects of the http request. Create new class which extends javax.servlet.http.HttpServletRequestWrapper and override methods getPathInfo() and getServletPath(). Give also that generated “sessionNNNN” block to constructor, so that those overriden methods can do their work.

Write getPathInfo() so that it first asks path info from super and then test if result contains that “sessionNNNN” pattern. If it is there, then remove it. Remeber that if result is now empty string, you must return null. See javadoc for those methods. Method getServletPath() must be changed so that you add that “sessionNNNN” to returned string. It helps if you add System.err.println and compare what these methods return without that redirecting stuff. Then you have better idea when you should return null, empty string and when there must be “/” at end and so on.

Last step is to use our wrapper class and wrap the http request with it and pass result to super class. Now Vaadin creates automatically new application instance for new tab, because the URL is different.

I also added new cookie containing “SESSION-ID” to response, but that’s not necessary. If you like to use cookies, remeber to add path to your cookies. The path you add is what you get by calling our.wrapper.class#getServletPath(). Without path all tabbed sessions sees same value for your cookie, which is probably not what you want.

So that’s my solution. There are some things to consider. If you are using authentication packages, does it work correctly because the http session is same? Cookies doesn’t work as expected unless they have their path set. What you want to happen if user copies URL from one tab to another? You propably need to check if URL is copied and then create new session. Hint: The URL is most likely copied if it contains that session string, but there is no “referer” http header in the request. The missing “referer” is also way to find when new browser tab is connecting to your application. There should be perhaps some kind of expiration system to prevent use of old tabbed sessions.

If someone is interested in example codes, I can provide them.

Hi,

I think that’s possibly a bit of a sweeping statement; for your particular use-case that may be true, but I specifically want to share an application for multiple tabs - different views, same application. I would suggest that’s a fairly common use-case.

There has been some debate on the forums about using the term “Application”, which is a per-session object and not a per-web-application object, but once you get your head around that, I personally feel do not feel that it’s an enormous problem.

Simply put, you can’t - at least, not in an application-server agnostic way. (You may be able to fiddle around forcing the session ID to be part of the URL in some containers, e.g. Tomcat, but - from memory - the default session identification method for application severs is via a cookie).

Typically, you can only force a new session from a new instance (or process) of the browser.

That all being said, it’s sounds like you’ve done well in solving your particular problem. Good Stuff!

Cheers,

Charles.

Hi Niko. With the following statement, I’m just trying to help you spare some time:

“Vaadin 6 does not support browser tabs”

I could try to be nice and add “very well for now, built in…”. But the fact is that they need to redesign their API and we all put much hope in Vaadin 7.

In the meantime, you may want to use Navigator7 add-on, or to see its source how it manages tabs, URIs. It tries to workaround a few problems. It’s the most advanced code I’ve seen on that problem for Vaadin 6 so far.

Good luck.
John.

A HOWTO for supporting multiple table can be found here:

http://vaadin.com/web/joonas/wiki/-/wiki/Main/Supporting%20Multible%20Tabs

I’ve just finished 2 chapters of the Vaadin Fundamentals course that explain the problem (but no solution, sorry, for that see Joonas’ link).


Application


Windiows

Hi John,

When I wrote my message, I had already written all necessary java code, which is one class about 100 lines of code. I knew that Vaadin doesn’t support browser tabs and thats why I created my solution. Now Vaadin support browser tabs and I’m happy.

regards, Niko

Hi Jonas,

I read that document before creating my solution, but I wasn’t happy with it. Neither I liked that Navigator thing. I have designed my application so that all new windows are added directly under main window. You examples doesn’t work if you use code like:

getMainWindow().addWindow(window);

The problem is that all new windows are now shown in first browser tab, because getMainWindow() returns main window for the first browser tab only. In my application I have separated window code from business logic, which knows the application instance, but it doesn’t see the currently open window instance. Therefore I cannot add new window as child window of the current one. There are also other reasons why I needed better solution.

Vaadin application class is designed to have only one main window. Trying to change that without redesigning whole window and application infrasturcture causes lot of small problems and you have to write many hacks into your code to overcome them.

My solution suits for my needs. Now I’m using application class as it is designed to work and I don’t need any special hacks in my code. Actually my code could be added to normal Vaadin ApplicationServlet class and parametrized so that those users who like to have it enabled could do so. But because nobody else seems to need separate browser tabs, I think it’s better not to add this feature to Vaadin.

regards, Niko

Can you post a simple app (one window, two tabs), it is often easier to grasp concepts by staring at a concrete example.

This included zip contains three maven projects demonstrating how Vaadin works with multiple browser tabs. You can build them separately and put results to TomCat or you can run them within Eclipse and TomCat. I used java 1.6, Eclipse Helios, Maven 3.0.1 and TomCat 6.0.29 for my tests.

First project is TestVaadin1. It demonstrates how Vaadin works without any tweaking. You will get out-of-sync errors if you use same test URL with multiple browser tabs.

Second project is TestVaadin2. This works roughly about how Vaadin people tells you to build multiple tab support. It works mostly, but you can still get out-of-sync errors and some windows doesn’t appear where you would like them to be. Of course, that problem can be fixed, but I wanted to demonstrate that this solution is far from perfect. You have to design your application logic special way to overcome this kind of problems.

Third project is TestVaadin3 and it is my new solution. It works without out-of-sync errors as long as you don’t copy and paste existing session URL to new tab. I think that problem can be prevented by using browser session level cookies, but currently there is no code for it. But maybe someone wants combine TestVaadin2 and TestVaadin3 examples so that end user can have separate browser tabs, but he or she can also split session windows to more than one browser window.

The code is quite compact and there are only few comments. I splitted the code into two classes, so unlike I previously wrote there are now two classes instead of one and there are little more than 100 lines of code.

If you have existing war application, it may be enough to copy RequestWrapper and TestServlet and change web.xml and your application has then multiple browser support. Same idea works also with OSGi web applications, although you need somewhat different code there.
11557.zip (21.8 KB)

In my humble opinion numbers in URLs are invasive. I feel (technical intuition) that the solution is in changing something deep in Vaadin core (not fundamental but deep enough to be too obscure for me), that will include what we all propose (one main Window instance per tab). In the new API, one Application would have multiple main Windows. setMainWindow() method is replaced by addMainWindow() (and they should not even be exposed, window instantiation should be transparent).

In that frame, I don’t see one Application instance per HttpSession, shared by all the tabs, as a problem.

What was the initial philosophy/intent, Joonas?
One Application per active user or one application by visual main Window? (or both ;-)?

The answer of Joonas apart, the servlet specification (in which Vaadin has to live) 's philosophy is one HttpSession shared by all tabs, and I would not change that if we have other options.

That being said, another version of my question to you, Joonas, is: would you

  1. Keep one Application per HttpSession and have multiple main Window per Application?
  2. Have multiple Applications per HttpSession (one per tab) and keep one Window per Application?

I don’t think you John has to be worried about this solution. It won’t be part of Vaadin anyway and therefore you don’t have to worry that this could cause problems for your own applications. Just relax. I need this solution, because my application must have separate browser windows.

Think how it would be if for example would Google work like Vaadin does now. If you open www.google.com with two broser tabs, both tabs would show same searchs results. Performing new search on one session would destroy result on the other or at leas force you to re-run the search. I would really hate that kind of behaviour and I believe there are many others like me. But fortunately Google has independent tabbes sessions.:rolleyes:

I would definitely prefer to have multiple windows per application.

Main window is definitely confusingly named. It should have been DefaultWindow. I any case - I hope we could just drop the whole MainWindow concept in 7 to make Vaadin simpler in that respect.

And some good news. It looks like Vaadin 7 design and API prototyping are finally starting for real shortly. Window API updates are the first and the most important updates that will be done.

Joonas,

I would like to verify one more detail about the following statement:

[i]

Have multiple Applications per HttpSession (one per tab) and keep one Window per Application?
[/i]

I tested the situation where WindowA is created by ApplicationA, and WindowB is created by ApplicationB. When I access WindowA in browser tab #1 and Window B in browser tab #2, I never get “Out of sync” situations and everything seems to work normally.

Is it supposed to work correctly this way? Is it really safe? If it works, this could be a good enough workaround to the problem until Vaadin 7 is ready.

I would go with one app, multiple windows: then you have full control on URL:s. With multiple apps, you would have to deploy apps in different uri:s.

Hi guys,

I am using Spring Security 3.1, Spring framework and Vaadin 6.8.

Based on the TestVaadin3, now, I can login the web application with username A in a browser A and login with username B in a separate browser B.

For my understanding, two application instances are instantiated for browser A and browser B respectively because of the prototype scope.

Now, I get the problem of logout.

In the init( ) function, I set the setLogoutUrl(‘/GP-CAMS-01/j_spring_security_logout’). When I click a button in browser A in order to logout. The getApplication( ).close( ) will be called and the Vaadin framework will further call setLogoutUrl function to execute.

The problem is that,
When I click a button to logout in browser A, there is an communication problem error prompted in browser B. I read the logging files. I guess that the two browsers are sharing the HttpSession. Therefore, I logout one of the browsers, the HttpSession sets to be expired and the Spring security authentication is no longer valid. Then, the other browser occurs “Communication Problem”. Is it correct?

If so, how to solve it? Any ideal?

Thanks.