Handling multiple windows navigating to web app and avoiding corrupted sess

Hello,

What is the best way to handle the situation when the user accidentally navigates in two windows to your web application? I’m not sure if many others have had this issue.

This is causing a big problem with my web application. My web application has a login screen. I first navigate in one window to my web application and then login. In that same window, if I navigate to a different website and then navigate back to my web application, the web application will be where it left off (I know this is expected, as it considers it to be the same session), which is fine.

However, if I open another window and navigate to my web application it will start at the login screen (it starts a new session). This causes a problem in the first window. Specifically, all the images start pointing to the wrong location and when I try to open any child windows in the first window nothing shows up. Basically, the new session created from the second window completely corrupts the first (still running) session.

Here is the first session before opening the second window:

Here is the first session after opening the second window:

As you can see, the images where the graphs were both have turned into button images somehow.

How can I workaround this? Is there a way to detect if my first session is still running and then force any other sessions trying to be created to fail?

Please help.

Thanks,
Ajay

Hi Ajay,

what is your web browser type/version ?

Actually it should not happen as while your session cookie exists, you should be able to come back to your application session from any browser window.

I just checked from my mac (Safari + FF3) and it is working as expected. Cannot check from a Windows machine right now but as I remember, it worked there as well.

Hi,

IT Mill Toolkit fully supports multiple windows, and does not start a new session when you open a new window (actually, I think you can configure IE to behave like that, but not FF afaik).

Windowing requires your application to take a few things into consideration, though: remember that the same component instance cannot be added twice to the application. This is real easy to do when having multiple windows.
For windowing, you should do something like:

       // Supports multiple browser windows
    @Override
    public Window getWindow(String name) {
        Window w = super.getWindow(name);
        if (w == null) {
            w = new MyWindow();
            w.setName(name);
            addWindow(w);
        }
        return w;
    }

…and encapsulate everything in MyWindow (be careful with the statics).

Actually, I’m not at all sure this is what’s causing your problem, because I don’t know what you mean when you say that the session is getting corrupted. And also, I don’t see why the login window appears again…
If you want, you could describe a little more how your application works, and exactly how the corruption manifests itself, and I’ll make a more educated guess :wink:

But the bottom line is this: it’s possible to make multiple windows work. The new ‘Sampler’, for instance, relies on windowing: you can open any sample in a new window, and browse the Sampler with multiple windows.

Hope this provided at lest some pointers!

Best Regards,
Marc

Update: there was a but in the getWindow() code. Sigh.

dll, I’m using IE7.

Marc,

At the moment, my main window creation looks like:

		// Create the application main window
		main = new Window(title);
		// Set the application main window
		setMainWindow(main);

And after this the login/password prompt is displayed with a submit button. When this submit button is clicked, the click listener will check if the typed login/password is correct. After this point, it will remove the login components from the main window and create rest of the application components. So it appears, a second window being opened is creating another session because the login screen shows up again meaning that it started from the beginning of init().

Perhaps my window creation is incorrect. I’ll take a closer look.

Thanks for the pointers :slight_smile:

Ajay

Hi Marc,

I downloaded the latest examples source and read through the “Sampler” example you described. I modified my application to run as that application is, but I am still facing the same problem. This is occurring in both IE7 and Firefox.

To make things a little more clear, I have stripped down the code used during my login process. Maybe you can see what is causing it:


public class MainWindow extends Window {
public MainWindow(Application a) {
		final VerticalLayout mainLayout = new VerticalLayout();
		setLayout(mainLayout);
		
		// Get the application reference
		myapp = a;

		// Check if the encryption password has been set
		if (!passwordSet) {
			// Set password key
			textEncryptor.setPassword(PASSWORD_KEY);
			passwordSet = true;
		}
		
		// Add login prompt
		final TextField loginPrompt = new TextField("Login:");
		// Add password prompt
		final TextField passPrompt = new TextField("Password:");
		// Make password text field secret
		passPrompt.setSecret(true);

		// Add login prompt to layout
		loginVL1.addComponent(loginPrompt);
		// Add password prompt to layout
		loginVL1.addComponent(passPrompt);

		// Create login button
		Button loginbutton = new Button("Login");

		// Add login button the layout
		loginVL1.addComponent(loginbutton);

		sp.setFirstComponent(loginVL1);
		// Add layout to main window
		mainVL.addComponent(sp);
		
		// Define listener for login button
		loginbutton.addListener(new Button.ClickListener() {
			public void buttonClick(ClickEvent event) {
				// Get the login typed by the user
				String inputLogin = loginPrompt.getValue().toString();
				// Get the password typed by the user
				String inputPassword = passPrompt.getValue().toString();

				String encryptedPassword = null;


				} else {

					// Check password

					// Compare the typed password with the encrypted
					if (passwordEncryptor.checkPassword(inputPassword, encryptedPassword)) {
						loggedIn = true;

						// Check if we successfully logged in
						if (loggedIn) {
							// Hide the login layout
							//loginVL1.setVisible(false);
							mainLayout.removeAllComponents();

							// Instantiate tab objects
							monitoring = new Monitoring();
							reports = new Reports();
							database = new Database();
							administration = new Administration();
							logAnalyzer = new LogAnalyzer();
							solutionWizard = new SolutionWizard();

							// Create logout button
							mainHL1.addComponent(new Button("Logout", new Button.ClickListener() {
								public void buttonClick(ClickEvent event) {
									loggedIn = false;
									// Shutdown the application
									myapp.close();

								}
							}));

							// Add main layout to main window
							mainLayout.addComponent(mainHL1);

							// Create main tabsheet
							mainTabSheet = new TabSheet();
							// Set dimensions of tabsheet
							mainTabSheet.setWidth(1160, Sizeable.UNITS_PIXELS);
							mainTabSheet.setHeight(560, Sizeable.UNITS_PIXELS);

						}

				}
			}
		});
}
}

Thanks,
Ajay

Hi,

You might want to put a debug-message in your MainWindow constructor, so that you can see when a new window is made, and when the old one is used.
Or better yet: in getWindow();

Which brings me to the point: overriding getWindow() is a must to make multiple windows work. It must return a new Window when a new window is requested.

After that is sorted, in your particular case, you’ll want to have a application-wide variable indicating that the user is already logged in, so that you don’t show the login again - remember, it’s a new window instance, so it does not know the stat of the old window unless you tell it.

One final note: when enabling windowing in an existing application like this, I’ve found that it’s quite easy to accidentally share a component instance between the windows, causing strange things to happen.

I’ll see if I can whip up a quick windowing + login example.

Best Regards,
Marc

Here is the full code for a login-example which supports multiple windows:

package com.itmill.toolkit.demo;
import com.itmill.toolkit.ui.Button;
import com.itmill.toolkit.ui.Label;
import com.itmill.toolkit.ui.TextField;
import com.itmill.toolkit.ui.Window;
import com.itmill.toolkit.ui.Button.ClickEvent;

public class HelloWindow extends com.itmill.toolkit.Application {

    @Override
    public void init() {
        setMainWindow(new MyWindow());
    }

    // Supports multiple browser windows
    @Override
    public Window getWindow(String name) {
        Window w = super.getWindow(name);
        if (null == w) {
            w = new MyWindow();
            w.setName(name);
            addWindow(w);
        }
        return w;
    }

    public class MyWindow extends Window {

        public MyWindow() {
            // check if the user is logged in - we'll use get/setUser()
            if (null == getUser()) {
                showLogin();
            } else {
                showMyStuff();
            }
        }

        private void showLogin() {
            final TextField login = new TextField("Login");
            addComponent(login);
            final TextField password = new TextField("Password");
            password.setSecret(true);
            addComponent(password);

            addComponent(new Button("Login", new Button.ClickListener() {
                public void buttonClick(ClickEvent event) {
                    // we'll accept anything except null
                    if (null == login.getValue()) {
                        showNotification("Nope.");
                        return;
                    }
                    // mark user as logged in, update UI
                    getApplication().setUser(login.getValue());
                    removeAllComponents();
                    showMyStuff();
                }
            }));
        }

        private void showMyStuff() {
            addComponent(new Label(getUser() + " logged in."));
            TextField tf = new TextField(
                    "This is independent from the other windows.");
            tf.setImmediate(true);
            addComponent(tf);
        }
    }
}

As you can see, the session will be intact, and the windows can share information (in this case via the application.getUser()), but also have independent information (the textfield in this example).

Hope this is useful.

Best Regards,
Marc

Marc,

Thank you for taking the time to write up a windowing+login example for me. I haven’t the chance to test it out yet, but I’ll let you know how it goes.

Much appreciated!
Ajay

Hi Marc,

I tested your windowing+login example in IE7 (and IE6). When first going to the app I see:

If I then close the window and open another and go to the same app, I see:

It doesn’t seem to be keeping the session intact (as I’m experiencing in my application also).

In contrast, I did test this in Firefox and the session remained intact after closing the window.

It appears that the session doesn’t remain intact in either version of IE 6 or 7 (for me at least).

Please help.

Thanks,
Ajay

Hi,

You’re probably starting a new browser session then. IE has a tendency to start a completely new, independent browser session when started from the menu.
Try opening a new tab or window from the browser (CTRL-T or CTRL-N, or using the menu).

That is:
If you browse away from the page and come back, or open a new tab/window from the browser, you’ll get the same session.
If you start a new browser, you’ll get a new session.

Most other browsers keep the same session unless you close the last window (and thus the browser), but IE works a little differently.

Hope this explains your problems…?

Best Regards,
Marc

Ajay, if you open the same URL in a new tab or new window but without closing the first one - will session survive ?
It is typically IE just removing cookies as it opens new application instance.

P.S. As for login prompt - Im usually making the separate window with
login-only interface which the only and main window in the application,
once login is validated, the normal window(s) are created and new main
window (with actual app interface) is set. You may also check the sample
here http://dev.itmill.com/wiki/Articles/ImplementingUserAuthentication

This is definitely a better way to do it ‘for real’ than swapping the components as in the small example I posted earlier.
Note that if you’re using multiple windows, you’ll have to change all windows back to the login screen if the user logs out - not just the main window (you’ll probably want getWindow() to check wheter or not the user is logged in).

Many applications also show some of the information even if you’re not logged in, and allows you to log in to do more. In this case you might want to open a login popup window or show a separate view when the user clicks ‘login’, then mark the user as logged in.

Best Regards,
Marc

dll and Marc again thanks for your replies.

If I run my application, and then I create a window or create a tab from within the same IE window and navigate to my application, the session is preserved and I have a message saying that the “user is already logged in” and it doesn’t let the user login again. This is the behaviour I have put in place to avoid having the browser sessions conflict (which is not really working, since it’s only working in the case of tab/windows created from an existing session).

The problem is, what if a user accidentally opens a FRESH IE window (not from an existing IE window) and navigates to my application. In that case, the login screen will come up and a new browser session is created (in the new window) and this is causing a problem in the OLD browser session.

The old session’s images change and the buttons stop responding. I guess the real question is, what is causing the conflict between the sessions? Is there a way to manage different sessions?

Thanks,
Ajay

Hi, Ajay,

unfortunately you cannot handle “fresh window” behavor and prevent framework from creating new sessions - as session cookie lost in the client browser, toolkit cannot recognize it anymore and have to start a new application.

As solution, you may define a static variable in your application i stance, where to store login flag (if you wan your application to handle one and only user) or a list of flags/addresses if you want to allow only one session per client machine. So, checking this flag(s) on application init, you may catch second+ session situation and construct an access denied window instead of initializing real application windows. But be careful with this - if user end up working with your application by just closing the browser and not the logout button of your application - session at the server side will remain until the application session timeout occurs, so you have to develop a way to handle such situations.

Regarding your resources mixup on multiple sessions - actually this shouldn’t happen. I think this may be some kind of mistake in your code, maybe because static fields with resources? Will the same mixup happen if you open multiple sessions from different browsers on the same computer - IE and FF for example? And if opened from two different computers ?

dll,

Between multiple browser types the problem will persist. I think you are correct in your suggestion that it may be a mistake in my code.

I am using quite a few static variables (probably a few where I shouldn’t) and this is most likely causing the issue.

I’ll take a closer look and let you know what happens.

Thanks,
Ajay

Hi dll and Marc,

I was able to resolve the so-called “corrupted sessions” issue.

I had a few classes referencing a static reference to the main window and this was causing the problem. I removed the static references and everything is working now.

Thank you both for your time!
Ajay

Hi, Ajay, glad to hear you successfully resolved the problem !