Hello guys,
I use the ThreadLocal pattern (with the TransactionListener) to get the Application instance corresponding to the request, from anywhere and it works fine.
// in MyApplication
static protected ThreadLocal<MyApplication> currentApplication = new ThreadLocal<MyApplication>();
@Override
public void transactionStart(Application application, Object transactionData) {
if (getCurrent() == null) {
currentApplication.set(this);
}
}
@Override
public void transactionEnd(Application application, Object transactionData) {
currentApplication.remove();
currentMainWindow.remove();
}
My application has a main window (of type MainWindow) that I set in the Application.
// In MyApplication.init()
this.setMainWindow( my new MainWindow )
In my overridden MyApplication.getWindow(name), I do create other instances of MainWindow, one for each browser’s tab that the user opens.
Its means that I cannot use:
Window win = MyApplication.getCurrent().getMainWindow();
because it does not take the browser’s tab into account, it always returns the window of the first tab.
I need the MainWindow instance of the tab from which the request has been sent, of course.
To do that, I applied the ThreadLocal pattern to MainWindow.
// In Myapplication
static protected ThreadLocal<MainWindow> currentMainWindow = new ThreadLocal<MainWindow>();
public static MainWindow getCurrentMainWindow() {
return currentMainWindow.get();
}
@Override
public void transactionEnd(Application application, Object transactionData) {
currentApplication.remove();
currentMainWindow.remove();
}
As far as I know, I cannot initialize it in the TransactionListener.transactionStart() method, because at that level, it does not tell which window/tab is concerned.
I initialize the threadLocal in MyApplication.getName(name), because there, I’ve a reference to the MainWindow corresponding to the current request.
And it works fine, except …
I’ve a login sub-window (as many applications) containing com.vaadin.ui.LoginForm (as I guess it’s the best practice from Vaadin). That form is very special. When the submit button is pressed, a “unusual” request is sent. Application.getWindow(name) is called with a strange name (“loginHandler”), but not with the main’s window name => I cannot initialize the MainWindow’s thread local, I don’t know the value.
Then com.vaadin.ui.LoginForm.LoginListener.onLogin() method is called.
Inside that method, I obviously check if the user exist and if the password is correct.
Still inside that method, I decide that the login corner (top right part of the page as most web applications) should be updated with the user’s name.
Aaaaargh! I need a reference to the correct MainWindow for doing that.
In fact, it’s ok, because I better update the top right corner of every tab => I user Application.getWindows() and update every window’s login corner.
But then I need to refresh the current window (probably not the same data is shown for a logged in user). How to get a reference to the MainWindow in that case?
I’d like to call my home made method WindowUitl.refreshCurrentWindow(). That method would retreive the main window instance “out of the blue”.
For the moment, I see no other idea than cluttering my code with references of (main)Window that I pass from methods to methods; from classes to inner classes.
Questions
- Is there a better way (than the ThreadLocal) to know “out of the blue” the main window corresponding to the current request?
- If not, is there a better way to initialize the threadLocal than MyApplication.getWindow()?
I know it’s difficult, I’m sorry; it comes from common requirement.
Thank you in advance.
John.