Closing session in multitab

Hi,

I have a problem when I have more than one tab or window with the same session.

To log out I first used this code:

     getSession().close();
     navigator.navigateTo("login");

This worked fine in the sense that when I logged out from a tab, when I tried to perform any action in the second tab I got a “Session Expired” notification. The problem with it is that when I try to log in again after being redirected, the first time it fails, showing Session Expired again. When I click the “click here to continue”, then I can log in.

Then I saw in some code examples that the correct way to log out is using getPage().setLocation(String uri).
I tried to change navigator.gotoLoginView(); for setLocation (even I don’t know exactly what should I set in the uri parameter). Now it works perfect with a single tab, but when I log out from one tab and try to perform an action in the second one I don’t get redirected or any message error, I get a page without content.

What is the correct way of handling log out with several tabs?

Thank you!

I found out that the multiple tabs have nothing to do with the problem. When I log out I redirect to the login page but I always get the “Session Expired” message when trying to log in again. When I press on the “Session Expired” message I get redirected to login again and then it works.

My logout code right now is as follows, in a method in MyVaadinUI:

mainLayout.logout();
getSession().close();

this.close();
navigator.gotoLoginView();

Any help in managing logout will be appreciated.

Thank you

To Logout you should generally just do session.close and page.setLocation(…).
You shouldn’t use the navigator after you closed the session and/or the UI you attached it to because it shouldn’t exist anymore.

If your app is called “test” for example i would recommend you to do this:

session.close(); Page.getCurrent().setLocation("/test"); This will bring your app in the original state when you first called it in a browser.
To do something like this in multiple browser tabs you might have to setLocation in every tab separately when you logout.

Oh, now I see why I had the problem with the multiple tabs…
When I use the setLocation method, instead of seeing the “Session Expired” message when I try to perform any action in the second tab (session closed form the first tab), the app tries to rebuild the actual page, and the result is a page without content.

Any idea of how to handle this?

Thank you!

New information that can be very useful.
I realized that there are two behaviours:

Common:

  • Open tab 1. Log in.
  • Open tab 2. You get logged in automatically.

Scenario A:

  • Log out from tab 2.
  • Try to perform an action in tab 1 → Strange reload of page with empty content (Console: WARNING: RPC call to com.vaadin.shared.ui.button.ButtonServerRpc.click received for connector 59 but no such connector could be found. Resynchronizing client.)

Scenario B:

  • Log out from tab 1.
  • Try to perform an action in tab 2 → “Internal error” message (Console: javax.servlet.ServletException: No UIProvider returned a UI for the request.)

This is what i think happens:

Scenario A:
The Session wasn’t closed in the main UI and a new one was created because of setLocation
The old session and all containing components got garbage-collected including the connector of the Button.
The App tries to find the components of the old ui in the new session created by the second tab but fails because the connector 59 doesn’t exist yet. → Exception empty page

Scenario B:
The Session was closed from the origin UI.
The action in the second tab causes a UIDL request which fails because the mentioned UI doesn’t exist in the current session. → Exception

Depending on how you use multi-tab support you should avoid these exception from happening right when you logout.

So… is there a way to notify all the other UIs that the session is closed?

My idea of multiple tabs is simply that if you open a second window that window should have the same session as the first one. And when you close the session from any of the windows that share session, the others should be able to handle it in an elegant way

I don’t know the best way to do it but the first way that comes to my mind would be to use
this
and send a VaadinSession variable with which you can check if the call comes from the same session.

I just found out that I can retrieve the UIs from VaadinSession getUIs method. Thank you very much for your help!

Hi,

Can anybody explain me why, having two tabs open of the same session, when the logout method is called both notifications are shown in the same tab? (with the different ids as caption)


public void logout()
{
    for(UI ui : this.getSession().getUIs())
    {
          ((MyVaadinUI) ui).showLogoutNotification();  
    }
}

public void showLogoutNotification ()
{
      Notification.show(this.toString(), Notification.Type.HUMANIZED_MESSAGE);
}

Thank you!

Notification.show(String, …) uses Page.getCurrent().

To show a notification elsewhere, you need to construct a Notification object and use the non-static Notification.show(Page). See the source code for Notification.show(*) for examples.

Oh, thank you Henri, I had tried that before but it didn’t work… but the problem is that I have to update the UI.

If I set the Refresher, without even a listener, then it works (I use Vaadin 7.0 and I don’t have push, planning to upgrade soon). So, can I do the same as the Refresher in some way? I’ve tried to remove the Refresher, mark the UI as immediate and then dirty but the notification doesn’t show.

No - without push, the browser has to make a request to the server to get any kind of updates. Web servers cannot contact browsers directly.

The Refresher simply makes requests periodically to check if there is something new.

Is there a way that I can make a single call to the server from the other UIs, when I logout from one UI? Refresher is giving me problems because it keeps trying to make server calls.
Whatever Refresher is doing, I want to do it once in a precise moment

The problem is that the browser (in the general case) cannot know when to make that call.

In your particular case, though, you might be able to write a JavaScriptExtension that communicates this information between browser tabs and triggers a new request. See e.g.
http://stackoverflow.com/questions/2236828/javascript-communication-between-tabs-windows-with-same-origin/12514384#12514384
for some information on how JavaScript can communicate between tabs. The localStorage approach is probably the best option if supported by all the browsers you need to support, which should be the case if you are using Vaadin 7.

I post my solution just in case it can help anybody. Probably is not the best solution, but I’ve tried a bunch of things and this is the only one that has worked for me.

What I have now is a solution with the Refresher that does the following:

  • I activate the refresher only after logging in.
  • When logging out I get all the UIs using getSession().getUIs() and I set a session logout flag to true.
  • For every UI (except the one that has called the logout method), I show a Notification saying what just happened. This notification will be shown next time the refresher executes. After showing the notification I stop the refresher and I increment a variable to count how many refreshers have I stopped.
  • In the refresher listener I have the actual logout procedure. This has a conditional and acts only when the number of refreshers stopped is getSession().getUIs() -1 and the logout flag has been set to true. This is because I only want to logout when I have pressed the logout, and because I don’t want to logout before the refreshers in al UIs have had time to show the message.

Feedback will be welcome