GWT - How to prevent certain functions from appearing in the JavaScript for certain users? - gwt

I'm conditionally building widgets for the GUI screen depending on the access level of the user. Even though the SuperUser widgets are not created and added to the panel for normal users, I can still find the presence of SuperUser widgets and (worse yet) the SuperUser functions inside the page's JavaScript. I've tried using code splitting (GWT.runAsync) but all that does is delay when the SuperUser functions are visible, it doesn't prevent them altogether.
if ("a".equals(userName)) {
// Create SuperUser widget that calls SuperUser function and add it to the layout panel.
} else {
// Create User widget that calls User function and add it to the layout panel.
}
The above creates both widgets and generates both functions in the JavaScript. I understand that GWT can compile in obfuscated mode, but we know that's only a "best effort" solution. Is there any way to get GWT to NOT include certain JavaScript functions unless explicitly told to include them? Ideally the SuperUser functions would only exist in the JavaScript if there's actually an execution branch that can access them.

Use Code Splitting mechanism:
To split your code, simply insert calls to the method GWT.runAsync at the places where you want the program to be able to pause for downloading more code. These locations are called split points.
In your case:
if("a".equals(userName))
GWT.runAsync(new RunAsyncCallback() {
#Override
public void onSuccess() {
// this code will be compiled to a separate file
// and downloaded when GWT.runAsync is executed
// Create SuperUser widget that calls SuperUser function and add it to the layout panel.
}
#Override
public void onFailure(Throwable reason) {
Window.alert("Code download failed");
}
});
else
GWT.runAsync(new RunAsyncCallback() {
#Override
public void onSuccess() {
// this code will be compiled to a separate file
// and downloaded when GWT.runAsync is executed
// Create User widget that calls User function and add it to the layout panel.
}
#Override
public void onFailure(Throwable reason) {
Window.alert("Code download failed");
}
});

If you are conditionally checking the user status at runtime in the browser, then the best you could do is to dynamically download a separate javascript library for the appropriate widget from the server and execute it. But this is pointless unless the javascript is protected on the server side based on server side authentication of the user.
Also, the GWT compiler compiles for applications, I don't think you can build a javascript library. (Though I could be wrong)

Related

Eclipse RAP multi-window/tab

I would like to have a multi-tab/windowed Eclipse RAP application.
I am able to open a second window using
UrlLauncher launcher = RWT.getClient().getService(UrlLauncher.class);
launcher.openURL("/gasf?foo=other_perspective");
Where I use the foo paramter to select the perspetive I want. However using this method will create a speparate http session, thus the various listeners and so on won't communicate with my first window.
I also tried opening a second window/page using
PlatformUI.getWorkbench().getActiveWorkbenchWindow().openPage("other_perspective" , null);
But this merely changes the current window perspective but does not open a second window or tab in my browser.
Has anyone achieved a multi-tab RAP application with working selectionlisteners between the tabs?
Thanks for any help you can provide
EDIT:
THANKS a lot ralfstx, as you pointed out, I can share the listeners or anything using the shared HTTP session, so far so good. Now the next step is to be able to update a tab based on an external event.
To try my idea of refresh from another tab, I did a dummy timer that does something 2 seconds later (i.e. simulate something triggered from another tab) with:
final ServerPushSession pushSession = new ServerPushSession();
pushSession.start();
Display display = Display.getDefault();
NavigationView navigationView = ((NavigationView) window.getActivePage().findView(NavigationView.ID));
timer.schedule(new TimerTask() {
#Override
public void run() {
display.asyncExec(new Runnable() {
public void run() {
navigationView.doSomething();
}
});
}
}, 2000);
This works! The pushSession.start() forces the UI to refresh without any user interaction. So now the action doSomething() is executed on the navigationView as soon as the 2 seconds are reached.
My only remaining concern is how much load this puts on the server, but its a reasonable solution at least. I validated your answer.
EDIT2:
Just to be complete, to make sure not bump in an invalid Thread access error since we are updating a display from another display, in the doSomething() method we must execute actions using display.asyncExec:
Display display = Display.getCurrent();
public void doSomething() {
display.asyncExec(new Runnable() {
public void run() {
treeViewer.refresh();
}
});
}
With the current architecture of RAP, you can't spread workbench windows over different browser tabs. Every new browser starts a new UISession which implies another Display (see Scopes in RAP).
However, the HttpSession should be the same (unless you have cookies turned off), so you could use this as a means of communicating between different browser tabs.

How to close a dialog in code?

So I'm making a eclipse plugin and I have a made my own dialog by extending the dialog class.
My dialog basically populates a treeview with data from a server. Sometimes the data cannot be populated (because the server is down) so my treeview is empty.
I have made another dialog appear reporting the error if I am unable to connect to the server.
My problem is that I would like to close the initial dialog when I press ok in the error dialog.
I have not been able to find a good way to do this.
I have tried setting setBlockOnOpen to false.
I have tried calling cancelPressed.
Neither of them have worked.
I called them in the createDialogArea function.
Any Ideas on how I could get this to work?
It is basically user cancelling dialog. you need to invoke cancelPressed() so it will be consistent handling if you have any code that depends on returnCode
if(noDataLoaded){
Display.getDefault().asyncExec(new Runnable() {
public void run() {
cancelPressed():
}
});
}
You need to do the close call after the dialog creation has finished. You can do this by using this code:
parent.getDisplay().asyncExec(new Runnable()
{
#Override
public void run()
{
close();
}
});
in your createDialogArea method. However the dialog may appear briefly. It would be better to do your check before creating the dialog.

Change opacity of a TreeItem

I have a server and client using gwt.
In my client page i have a tree item displayed.
I want to do one of the following:
- disable the tree item when a function is called.
- made opaque the entire client page or only the tree item when a function is called.
By made opaque, i want to do the same as occur when i debug my project with eclipse and i stop and i get the following in the client page
GWT Code Server Disconnected
Most likely, you closed GWT Development Mode. Or, you might have lost network connectivity. To fix this, try restarting GWT Development Mode and REFRESH this page.
Please give me some indication on how to do it and if it is possible.
you create a handler for you function call(s) and add the style when the funciton is called. Because GWT works with javascript it changes your appearance during runtime.
item.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
event.getItem().setStyleName("newStyle");
}
});
and in the css you define you style:
newStyle: {
...
your style definition
}

Best Practices GWT Event Handling

I have a question regarding the event handling on client side in GWT.
In our application we have a quite complex structure of different modules and pages which are communicating via the gwt eventbus on client side. Now the amount of events is growing to fast for my opinion. E.g. I am opening a popup I need:
An event for opening the popup
An event for asking some data within the client
An event for getting back the data and fill in the dialog
An event for closing the popup
An event for handling the save Button
Am I thinking a little bit to complicated or missing something in the EventBus implementation? I just wanted to have some feedback out of the community as you are facing the same issues.
For what it's worth, I have lots of events and more growing. And yes, I wonder if I can do with less, but when I skip an event and link elements directly, I regret it.
Here's an example that I just fixed up yesterday. I have a DataGrid widget. I also support re-ordering of columns, hiding of columns, re-sizing columns, and coloring columns with a popup dialog. You click on a configure button, and a popup with the columns listed shows, and the user can click checkboxes to show or hide columns, click on a Move Up / Move Down button to re-order columns, and so on. Hit Apply on the popup and the popup disappears and the DataGrid re-configures.
Except that it didn't. You'd click on Apply and the popup would just sit there, the user would wonder what was going on, the DataGrid would re-configure underneath, and then the popup would go away. We're only talking a short amount of time -- maybe a second or a bit more -- but it was so so noticeable. Why was it happening? Because I got lazy and tied the popup directly to the configure button, and the Apply button directly to the DataGrid. You'd hit Apply, for example, and the call would be made to the DataGrid with the new configuration information. Only when the call returned would the popup would be torn down.
I knew it was bad when I did it, but I was being lazy. So I took the 20 minutes I needed to write up two messages and associated handlers in my mediator singleton. One message is issued by the DataGrid to start the configuration dialog, and one is issued by the popup to configure the DataGrid. Now the widgets are de-coupled, and the performance is much snappier. There is no sense of "stickiness".
Now to your example, can you not combine (1) and (2)? And also (3), (4), and (5)? When the user clicks the configure button on my app, the event carries with it the current configuration information (including a reference to the DataGrid that originated the request). You can call this information the "payload". When the user clicks the Apply button on the popup, the event payload includes all the new configuration information (including a reference to that original target DataGrid) that the event handler feeds to the target DataGrid when the event is handled. Two events -- one to kick off the configuration and one to apply the end result.
Yes there are a plethora of events in any app that does something interesting, but events can carry a lot of information, so I would look at whether your event organization is too fractured.
As a extra bit, here is the code I use. I shamelessly copied elements of this pattern from one of Google's examples.
The user can ask for help using a menu item:
#UiField
MenuItem help;
help.setCommand(new Command() {
#Override
public void execute() {
BagOfState.getInstance().getCommonEventBus().fireEvent(new MenuHelpEvent());
}
});
For the event (in this case, the event fired when the user clicks on the Help menu item):
public class MenuHelpEvent extends GwtEvent<MenuHelpEvent.Handler> {
private static final Type<Handler> TYPE = new Type<Handler>();
public interface Handler extends EventHandler {
void doMenuHelp();
}
#Override
public GwtEvent.Type<Handler> getAssociatedType() {
return TYPE;
}
#Override
protected void dispatch(Handler handler) {
handler.doMenuHelp();
}
public static HandlerRegistration register(EventBus eventBus, Handler handler) {
return eventBus.addHandler(TYPE, handler);
}
}
I have a singleton called Mediator in which ALL events are registered:
MenuHelpEvent.register(BagOfState.getInstance().getCommonEventBus(),
new MenuHelpEvent.Handler() {
#Override
public void doMenuHelp() {
new MenuHelp().execute();
}
});
Every event is mated with a Command object to do the work:
public class MenuHelp implements Command {
#Override
public void execute() {
new InfoMessage(BagOfState.APP_MSG.unimplementedFeatureCaption())
.setTextAndCenter(BagOfState.APP_MSG.unimplementedFeature());
}
}
Everything is decoupled. The menu widget is bound to a command that executes and then completes. The command fires the event on the bus then completes. The event fires off the execution of a Command and the completes. The Command shows the popup help panel (in this case, an "unimplemented" message to the user -- yeah, I'll get to it soon). Every interaction with a user's input is handled extremely quickly and resolves. It can kick off a series of events to perform a long action, but never tying up the GUI to do so. And of course, since the elements are decoupled, I can call the same elements in other places (for instance, call the help Command through a button push as well as a menu item).

How to keep business logic seperate within GWT Composites?

I'm currently building a GWT login screen and I managed to get a basic version of the login structure working.
I created the following pieces:
An entry point class (actually it was given).
A main application screen composite.
A login-screen composite.
I have the following logic in my entry point method:
MyApplication mainWindow = null;
public void onModuleLoad() {
LoginScreen loginScreen = new LoginScreen() {
#Override
public String onLogin(String username, String password) {
boolean passwordWasOk = rpcCheckUsernamePassword(username,password); // mechanism not important for this question
if (passwordWasOk) {
RootPanel.get().remove(0);
mainWindow = new MyApplication();
// Using root layout panel as main window is a layout type composite
RootLayoutPanel.get().add(mainWindow);
return null;
} else {
return "password was incorrect";
}
}
};
RootPanel.get().add(loginScreen);
}
So, I created a method in the LoginScreen composite that is called when the user clicks the 'Sign-In' button. If the onLogin method fails its validation of the username and password, then a narrative can be returned to the login composite so that it can update the user. The login screen will stay on the screen until the user uses a correct username/password combination.
My question is, is this the correct way to use composites? Where should my login logic ideally reside. Is a better alternative to inject some sort of login handler object in the constructor of the composite or via a setter or is the method I used quite normal?
As I'm planning to write quite a lot of code, I want to get the coding style correct from the outset.
Any feedback is greatly appreciated.
Thanks,
For complex projects you'd want to use the Model-View-Presenter (MVP) design pattern. It allows you to separate the rendering logic (views) from the business logic. To get you started, the official documentation has two articles about it plus there's that presentation by Ray Ryan that started the whole GWT + MVP = <3 haze :) After that I'd recommend browsing through MVP related questions on SO and GWT's Google Group.