GWTP: clear presenters on logout - gwt

Im using GWTP in my GWT app and have the following architecture:
LoginPresenter (Presenter)
DashboardPresenter (TabContainerPresenter)
TabbedPresenter1 (Presenter)
TabbedPresenter2 (Presenter)
TabbedPresenter3 (Presenter)
The first time I start my app, the onBind and addTab methods are called in the DashboardPresenter and when I navigate to a tab, the onbind method is called on that presenter.
If I create a PlaceRequest and navigate back to LoginPresenter via my PlaceManager (by pressing a logout button), I return to the login presenter.
The problem is that if I login again, then all the onBind methods are not called because they are still in memory. onReset and onReveal are called correctly, but I would very much like that each Presenter are reset and that the onBind will be called on each login.
I decide on the login event which tabs should be visible for user and restrict tabs in the addTab method of the DashboardPresenter if the user does not have sufficient rights to see those tabs. But as of now, the tabs are setup the first time a user logs in, but not the next time. This means that if a user with lesser rights logs in after an admin user, he can see the same tabs as the admin. Not good!
How should I deal with this? I would very much like to "reset" all presenters or the session when a user logsout (navigating to the login page). Is it the Ginjector that needs to be "reset", so that it does not return the same binded objects as before?
Just to clarify: we do have server side security which prohibits users with no rights to access sensitive data. But when the user logs in, the gwt app receives a list of features which the user can access. This is used for customizing the UI to fit the rights of the user. (E.g. customize the visible tabs based on users privileges).

I am not sure if this work:
But you could try to fire a LogoutEvent on the global EventBus , handle it in all Presenters that need to be "unloaded" (TabbedPresenter1, etc) and call onUnbind() on them.
Afterwards navigate back to the LoginPresenter
Alternatively you could make us of a custom TabData (subclass TabDataBasic and add a flag hasAccess).
Again you fire a LogoutEvent and when you handle it you can do something like that:
TabDataDynamic tabData = (TabDataDynamic)getProxy().getTabData();
tabData.setHasAccess(false);
getProxy().changeTab(tabData);
In yout TabPanel implementation you have to make sure that the Tab is hidden, when the flag is set to false.

I think that you should take a look to GateKeeper which can be easily used with presenters like:
#ProxyCodeSplit
#NameToken(NameTokens....)
#UseGatekeeper( Your1GateKeeper.class)
public interface MyProxy extends TabContentProxyPlace<YourPresenter> {
}
And you can inject a Dashboard presenter to GateKeeper to check is this tab available:
#Singleton
public class Your1GateKeeper implements Gatekeeper{
private DashboardPresenter presenter;
#Inject
public ReadOnlyGateKeeper(DashboardPresenter presenter) {
this.presenter = presenter;
}
#Override
public boolean canReveal() {
return presenter.isAvailable();
}
}
So using appropriate GateKeepers will allow you to reach required security.

Related

How to fix the delemma in control the gui when user logins in GWTP?

Ok, here is my dilemma:
I got a Header presenter which is the nested presenter. The Customer presenter is the child of Header presenter (ie the Customer presenter was put into a slot of Header presenter).
There is Login Panel in Header presenter.
-So here is the requirements:
-Users can not see any Gui of Customer presenter if they have not logged in yet.
-When the user logins successfully then it will visible the Gui of Customer presenter.
-When User refreshes the page, the system will check if the customer logined. If he/she did login, then the system will show Gui of Customer presenter. If he/she has not logined, then prompt an error message.
So here is what I did.
In Header presenter, I have a method loginedSuccessfully(), this method will passUserInfo() (use eventBus) into Customer presenter.
In Customer presenter, I have:
private int custID=0;
public void onReset(){
super.onReset();
if(custID>0){
showGui();
}
else{
hideGui(); // the hideGui() has Window.alert("Pls Login");
}
}
private PassUserInfoHandler passUserInfoHandler=new PassUserInfoHandler(){
#Override
public void onPassUserInfo(PassUserInfoEvent event) {
custID=event.getCustID();
if(custID>0){
showGui();
}
else{
hideGui();
}
}
};
When user refresh the Customer page. The onResetwill be called, if customer has not logined yet then it won't show Gui & prompt a message.
When user logins by clicking login button then passUserInfoHandler will be called & it will show the Gui if logged in ok.
But here is the problem. When user already logged in & if I open a new browser Tab & re-open the Customer page, then this time both onReset & passUserInfoHandler waere called & the page prompts the message TWICE. This is not Good.
But why that happened?
This is because the onReset was called before the passUserInfoHandler was called. That is why checking gui method was called 2 times.
I used Scheduler.get().scheduleDeferred(new Command() {}; but it didn't work.
Do you know how to fix the problem so that it can meet all the above requirements?
GWTP is full fledge architecture. It's also have such API that, you can prevent some presenters from revealing themselves by creating your custom Gatekeeper classes. For example, if you want some presenters to be accessible only when the user is logged in you could write the following class:
#Singleton
public class LoggedInGatekeeper implements Gatekeeper {
private final CurrentUser currentUser;
#Inject
public LoggedInGatekeeper (
final CurrentUser currentUser ) {
this.currentUser = currentUser;
}
#Override
public boolean canReveal() {
return currentUser.isLoggedIn();
}
}
Then you simply need to add the #UseGatekeeper annotation to the proxy of each presenter you want to protect:
#ProxyCodeSplit
#NameToken("userSettings")
#UseGatekeeper( LoggedInGatekeeper.class )
public interface MyProxy extends ProxyPlace<MainPagePresenter> {}
I think you should go for it, instead of write manually stuff. Even once may be your code work. but in feature some new bug will be raise in your code. you can refer this GWTP.

What is the best way to allow page refresh in gwtp?

I am beginner in gwtp and I want to build an application that displays a list of products, and by clicking I displays the details of the selected product...
My question is how to refresh the page to allow page product Detail to refresh while respecting security measures, obviously I do not want to pass the id of the product in the request.
I thought about storing the id in the session but I do not know if it will impact the application's performance given the high response times of RPC.
Any help or clarification on this would be appreciated.
You might consider using GWT's Cookie Support. Properly implemented, you'd always know exactly what they were doing last and getting them back to there becomes easy. Cookies are obviously client-side, so it's always going to be faster than RPC.
I have some advice but be aware I'm fairly new to GWTP as well....
Security
Communication should take place over SSL/HTTPS. I put it across my entire app using the servlet container (web.xml) so that it integrates seemlessly with non-GWT parts of my app.
I don't see a problem with putting an 'id' in a url. You can always prevent it from showing in the address bar with PlaceManager.revealPlace(PlaceRequest, boolean).
Composed View
I have a view with a list of entities on the left and the edit form on the right. The list is always shown and is placed in a 'slot' explicitly by a parent presenter:
public class Users extends Presenter<Users.View, Users.Proxy> {
#ContentSlot
public static final GwtEvent.Type<RevealContentHandler<?>> LIST_SLOT = new GwtEvent.Type<RevealContentHandler<?>>();
#ContentSlot
public static final GwtEvent.Type<RevealContentHandler<?>> FORM_SLOT = new GwtEvent.Type<RevealContentHandler<?>>();
#Inject
private UserList userList;
#Inject
public Users(EventBus eventBus, View view, Proxy proxy) {
super(eventBus, view, proxy, Configuration.SLOT);
}
#Override
protected void onReveal() {
super.onReveal();
setInSlot(LIST_SLOT, userList);
}
...
My app has an 'empty form' presenter which is shown by default when no list item is selected. This prevents the list and parent presenters from being a 'place' (requiring a token). Only the leaf presenters in the presenter hierarchy should be a 'place'.

How to manage the creation of instances when navigating

I am programming WP7 application adhering the MVVM pattern.
I have ViewModelLocator which ensures that each instance of ViewModel is only one. These ViewModels are created when application is launched. ViewModels communicating with each other using messages. I use messages for navigatig to next Page (For this I am using NavigationService.Navigate(), which is Raised from MainPage CodeBehind - it is the only functionality that is in CodeBehind ). View and ViewModels are connected together by setting the DataContext in the Page to ViewModelLocator.
Everythig works at first sight.
But during each navigation, there is created new Page instance, which is connected to the ViewModel from ViewModelLocator(which is designed for it). The result is that: when a user often switches between pages, there are multiple instances of a page connected to one ViewModel. Of course, there is visible only one page at one point.
Very simple solution could be setting NavigationCache, but it is readonly in WP7.
I am looking for solution of unwanted behavior.
Every time you Navigate somewhere a new instance is created for that page.
You could avoid this by using NavigationService.GoBack(); where ever you can.
You should also unregister from every event when navigating away from the page, so that way the garbage collector can clear out that page.
I hope this helps.
You may try to declare an instance of your ViewModel at App.xaml.cs, such as,
private static YourViewModel viewModel = null;
public static YourViewModel ViewModel
{
get
{
// Delay creation of the view model until necessary
if (viewModel == null)
viewModel = ViewModelLocator.MainStatic;
return viewModel;
}
}
Then from the page you will navigate to, you can reference it as App.ViewModel.
If your page is in different assembly form your main application, you could declare following in your App.xaml,
<vm:ViewModelLocator x:Key="VMLocator" />
Where vm referencing to your main app, then you can use is as following,
((ViewModelLocator)Application.Current.Resources["VMLocator"]).YourViewModel;
Hope it would help.

Using GWTs activities and places can I navigate to a previous page without using History.back()?

I am using GWTs Activities and Places pretty much as described on http://code.google.com/webtoolkit/doc/latest/DevGuideMvpActivitiesAndPlaces.html and it is all working fine.
What I would like to do is from a particular page navigate to the previous page without using History.back() as I don't want to lose the history state. (I have a page where the user performs an action, on success I want to return to the previous page and keep the history state, on the other hand if they cancel I do want to use History.back() as I do want to lose the state).
The only way I can think of to do this is to create my own Place/History tracking code that listens to Place/History change events and makes the previous Place available to me so that I can call placeController.goto(...)
Is there an easier way of doing this? Am I missing something?
The approach I took was to store the history token in code (as suggested). I extended PlaceController and used it to track Place changes on the EventBus. Now everywhere I was using PlaceController I instead use PlaceControllerExt which has a nice previous() method that takes me back to where I came from - but navigates forward and never leaves the application.
public class PlaceControllerExt extends PlaceController {
private final Place defaultPlace;
private Place previousPlace;
private Place currentPlace;
public PlaceControllerExt(EventBus eventBus, Place defaultPlace) {
super(eventBus);
this.defaultPlace = defaultPlace;
eventBus.addHandler(PlaceChangeEvent.TYPE, new PlaceChangeEvent.Handler() {
public void onPlaceChange(PlaceChangeEvent event) {
previousPlace = currentPlace;
currentPlace = event.getNewPlace();
}
});
}
/**
* Navigate back to the previous Place. If there is no previous place then
* goto to default place. If there isn't one of these then it'll go back to
* the default place as configured when the PlaceHistoryHandler was
* registered. This is better than using History#back() as that can have the
* undesired effect of leaving the web app.
*/
public void previous() {
if (previousPlace != null) {
goTo(previousPlace);
} else {
goTo(defaultPlace);
}
}
}
You have to somehow keep track of were to return, because instead of cancel the user can hit the back button, which would be the same as clicking cancel, except there is no code in your application executed, so you have no control.
Secondly if you have the history in the url, the user could navigate directly to that page and then you should know where to go to when the user click ok. Or if the user goes directly to the page, redirect the user to another page.
One approach is to store the return history token in the history token of the page you go to. When the page is finished it can go back(or technically it would be 'go forward') to that page based on the passed return token. (Although with GWT you could easily store the history token in code).

How to handle UI interaction from view model without user request using MVVM, PRISM, and MEF

I am working on an application which is using WPF, MVVM, Prism, and MEF.
I am using a combination of navigation with request navigate, controllers with view management using region manager, and eventing via event aggregator to run the application in a single window. I'm using a view first approach similar to how the Stock Trader RI works.
This works great when any view model code that would interact with the UI (busy indicator) is kicked off by the user, but when it is started behind the scenes there can be problems.
I know this may seem like a poor implementation, but I think I have a valid scenario. My particular example has to do with login.
Currently the application starts and loads the shell. The login view is loaded into the main content region of the shell. When the user clicks "login" a busy indicator is shown and the client application services login is executed. When the login is complete, the busy indicator goes away, and the screen is navigated to the user's home screen.
This works well because the navigation login and navigation are initiated by the user clicking the login button.
So now I have a new requirement that a user can select Auto Login on the login form, such that the next time the user starts the app, the login view will not show up and login will happen behind the scenes.
Now if I just want to call the auto login feature, there is no problem, this by itself has no UI interaction and will work fine. But login takes a few seconds and I want to display my busy indicator.
The problem is where do I initiate the auto login call? The shell view model constructor? The shell view model PartImportsSatisfied implementation? In any of these places, the shell view (which contains my busy indicator) isn't really loaded yet. As a result, none of the resources I need, like regions and region managers aren’t available.
So what might be a good way for me to implement this:
Check if previous user should auto login (got this part figured out)
If yes then
Show busy indicator
Attempt to auto login
If auto login was success
Hide busy indicator
Navigate to user home screen
Else
Hide busy indicator
Navigate to login screen
Else
Hide busy indicator
Navigate to the login screen
Any ideas are greatly appreciated.
Implement an interface within your ShellViewModel which will deal with the concept of being loadable. Do not perform this logic within the constructor of the ShellViewModel as this is typically bad practice and should be used to instantiate objects at the most.
public class ShellViewModel : ILoadable
{
public ShellViewModel()
{
}
bool ILoadable.Load()
{
//this is where you can take care of your auto login
}
}
You could then call this within your Bootstrapper class. If this were being done within another module you could call it within the IModule.Initialize method.
I would also argue that this logic should get implemented within a service which could be called by the ShellViewModel as mentioned above or could in theory be called directly from the Bootstrapper class; allowing the ShellViewModel to potentially then make use of stateful data from within the service.