Waiting until application return Sucess or Failure(AsyncCallBack) - gwt

Just for example, let's check the code below
private void loadUserFromServer() {
dispatchAsync.execute(new FindLoggedUserAction(),
new AsyncCallback<FindLoggerUserResult>() {
#Override
public void onFailure(Throwable caught) {
//do something
}
#Override
public void onSuccess(BuscarUsuarioLogadoResult result) {
//dosomething with user
result.getUser();
}
operationTwo();
}
My problem is, I have to execute operationTwo(); after some result of dipatcher(Success or failure).
This is just an example, let's assume I can't put operationTwo() inside the onSucess or onFailure()
My real PROBLEM
My GateKeeper of presenters that user must be login.
private UserDTO user;
#Override
public boolean canReveal() {
if(getUser() == null){
ShowMsgEvent.fire(eventBus,"Must Login first", AlertType.ERROR);
return false;
}
return true;
}
}
public UserDTO getUser()
{
if(user == null)
{
//call server
loadUserFromServer();
}
return user;
}
private void loadUsuarioFromServer() {
dispatchAsync.execute(new BuscarUsuarioLogadoAction()
,new AsyncCallback<BuscarUsuarioLogadoResult>() {
#Override
public void onFailure(Throwable caught) {
//something
}
#Override
public void onSuccess(BuscarUsuarioLogadoResult result) {
if(!(result.getDto().equals(user)))
{
setUsuario(result.getDto(), false); //Set user UserDTO user
//event for update Presenter Login/Logout
// and Label with username
fireUserUpdateEvents();
}
else
{
setUsuario(result.getDto(), false);
}
}
});
As you can see, when a Presenter with that Gatekeeper is called and user is null,
getUser() is called, but when dispatch executes, the method doesn't wait until the return of Sucess or Failure
Result: getUser() returns null.
After the sucessful result of dispatch, getUser() returns a DTO. But, as you can see canReveal() already returned false.

Do not think that GateKeeper is a good approach to handle security in your case. You will not be able to reach stable work. Problem that you will have:
You are not handling network connection lost. If you code is already cached but you need to reload User it will be a big problem with double checking.
Sync calls are always problematic, specially with bad network connection. You will have tons of not responding messages.
To handle presenter access it will be better to use revealInParent method. Most of your presenter already overrides it and it looks like:
#Override
protected void revealInParent() {
RevealContentEvent.fire(...);
}
So you can just not fire Reveal event before you actually download user data. In your case the code will looks like:
#Override
protected void revealInParent() {
if(getUser() == null){
RevealContentEvent.fire(...);
return;
}
dispatchAsync.execute(new BuscarUsuarioLogadoAction()
,new AsyncCallback<BuscarUsuarioLogadoResult>() {
#Override
public void onFailure(Throwable caught) {
//something
}
#Override
public void onSuccess(BuscarUsuarioLogadoResult result) {
if(!(result.getDto().equals(user)))
{
setUsuario(result.getDto(), false); //Set user UserDTO user
//event for update Presenter Login/Logout
// and Label with username
fireUserUpdateEvents();
}
else
{
setUsuario(result.getDto(), false);
}
RevealContentEvent.fire(...);
}
});

We have also encountered similar problems. Its better to use Async call chaining. Since you can't do that there are two options for your problem
Setup a timer which will check from time to time whether the user is null or not and return only after when user is populated.
Use JSNI (Native code) and make the synchronous call. But beware this is bad practice

Yes, as Abhijith mentioned in previous answer there are 2 options -
1) Synchronous calls - which GWT doesn't support. So it is ruled out.
2) Setting timer - unless user logs in control will not come out of the timer loop. So failed status will never return from the timer. This approach serves only half of your requierment(serving only success state).
To solve your problem you try the following code snippet -
private UserDTO user;
private CanRevealCallBack revealCallBack;
public interface CanRevealCallBack {
returnStatus(boolean status);
}
#Override
public void canReveal(CanRevealCallBack callBack) {
revealCallBack = callBack;
if(user == null){
loadUserFromServer();
}
else{
revealCallBack.returnStatus( true );
}
}
private void loadUsuarioFromServer() {
dispatchAsync.execute(new BuscarUsuarioLogadoAction()
,new AsyncCallback<BuscarUsuarioLogadoResult>() {
#Override
public void onFailure(Throwable caught) {
//something
}
#Override
public void onSuccess(BuscarUsuarioLogadoResult result) {
if(!(result.getDto().equals(user)))
{
setUsuario(result.getDto(), false); //Set user UserDTO user
//event for update Presenter Login/Logout
// and Label with username
fireUserUpdateEvents();
}
else
{
setUsuario(result.getDto(), false);
}
if(result.getDto() == null){
revealCallBack.returnStatus( true );
}
else{
revealCallBack.returnStatus( false );
}
}
});
So, you have to pass a revealCallback to the canReveal method. CallBack gets executed and returns u the status on success of the async call. In returnStatus method of the callback you can program the logic with the correct user log-in status.

Related

When is it necessary to check if a subscriber is subscribed prior to calling onNext() and onError()?

Consider the following example, it creates an Observable that wraps another API that produces Widgets
public Observable<Widget> createWidgetObservable() {
return Observable.create(new Observable.OnSubscribe<Widget>() {
#Override
public void call(final Subscriber<? super Widget> subscriber) {
WidgetCreator widgetCreator = new WidgetCreator();
widgetCreator.setWidgetCreatorObserver(new WidgetCreator.WidgetCreatorObserver() {
#Override
public void onWidgetCreated(Widget widget) {
if (!subscriber.isUnsubscribed()) {
subscriber.onNext(widget);
}
}
#Override
public void onWidgetError(Throwable e) {
if (!subscriber.isUnsubscribed()) {
subscriber.onError(e);
}
}
});
}
});
}
Are the subscriber.isUnsubscribed() checks necessary prior to calling subscriber.onNext() and subscriber.onError()?
If so, are the checks always necessary or does it depend on the composition / subscriber that's using the observable?
Is it best practice to include the checks?
You can use them to narrow the window between an emission and an unsubscription but if you don't have loops, it is unnecessary most of the time. The more important thing is that if an unsubscription happen, you'd have to "unset" the WidgetCreatorObserver otherwise it will keep receiving and dropping data and keeping alive every reference it may hold.
WidgetCreator widgetCreator = new WidgetCreator();
WidgetCreator.WidgetCreatorObserver wo = new WidgetCreator.WidgetCreatorObserver() {
#Override
public void onWidgetCreated(Widget widget) {
if (!subscriber.isUnsubscribed()) {
subscriber.onNext(widget);
}
}
#Override
public void onWidgetError(Throwable e) {
if (!subscriber.isUnsubscribed()) {
subscriber.onError(e);
}
}
}
widgetCreator.setWidgetCreatorObserver(wo);
wo.add(Subscriptions.create(() -> widgetCreator.removeWidgetCreatorObserver(wo)));

My selection listener doesn't seem to be registering properly

I am creating an Eclipse RCP application with multiple views. One of my views is a multi-page editor view. Each of those pages has a a master/details block. I need to register all of those TableViewers as selection providers for my other view to listen to.
After much research online, I came across this article about multiple selection providers in a single view. I followed the instructions to create this selection provider for multiple viewers.
class MyMultipleSelectionProvider implements ISelectionProvider {
private final ListenerList selectionListeners = new ListenerList();
private ISelectionProvider delegate;
private final ISelectionChangedListener selectionListener = new ISelectionChangedListener() {
#Override
public void selectionChanged(final SelectionChangedEvent event) {
if (event.getSelectionProvider() == AdaptabilityProfileSelectionProvider.this.delegate) {
fireSelectionChanged( event.getSelection() );
}
}
};
/**
* Sets a new selection provider to delegate to. Selection listeners
* registered with the previous delegate are removed before.
*
* #param newDelegate new selection provider
*/
public void setSelectionProviderDelegate(final ISelectionProvider newDelegate) {
if (this.delegate == newDelegate) {
return;
}
if (this.delegate != null) {
this.delegate.removeSelectionChangedListener(this.selectionListener);
}
this.delegate = newDelegate;
if (newDelegate != null) {
newDelegate.addSelectionChangedListener(this.selectionListener);
fireSelectionChanged(newDelegate.getSelection());
}
}
#Override
public void addSelectionChangedListener(final ISelectionChangedListener listener) {
this.selectionListeners.add(listener);
}
#Override
public ISelection getSelection() {
return this.delegate == null ? null : this.delegate.getSelection();
}
#Override
public void removeSelectionChangedListener(final ISelectionChangedListener listener) {
this.selectionListeners.remove(listener);
}
#Override
public void setSelection(final ISelection selection) {
if (this.delegate != null) {
this.delegate.setSelection(selection);
}
}
protected void fireSelectionChanged(final ISelection selection) {
fireSelectionChanged(this.selectionListeners, selection);
}
private void fireSelectionChanged(final ListenerList list, final ISelection selection) {
final SelectionChangedEvent event = new SelectionChangedEvent(this.delegate, selection);
final Object[] listeners = list.getListeners();
for (int i = 0; i < listeners.length; i++) {
final ISelectionChangedListener listener = (ISelectionChangedListener) listeners[i];
listener.selectionChanged(event);
}
}
}
I added a focusListener on all of the edior's viewers so they become the delegate:
tree.addFocusListener(new FocusAdapter() {
#Override
public void focusGained(final FocusEvent e) {
editor.getSelectionProvider().setSelectionProviderDelegate(MyEditorPage.this.treeViewer);
}
});
And I registered this as the selection provider for my editor:
site.setSelectionProvider( this.selectionProvider );
Then, within my view that needs to hear about the selection, I registered a selection listener for this editor:
getSite().getPage().addSelectionListener(MyEditor.ID, this.selectionListener);
When I run the application, I see that the delegate is being changed and the selection events are being fired. However, the listener list is empty.
I am never calling addSelectionChangeListener() directly. I was under the impression that that was what the selection service is for. Am I wrong? Should I be calling it? If so, when? If not, who is supposed to be adding the listener, and why isn't it happening?
If your code is based on FormEditor (or MultiPageEditorPart) then the selection provider is set to MultiPageSelectionProvider at the end of the init method. This may be overriding your site.setSelectionProvider call.
Using:
#Override
public void init(IEditorSite site, IEditorInput input)
throws PartInitException {
super.init(site, input);
site.setSelectionProvider(this.selectionProvider);
}
should make sure your provider is the one used.

execute asynccallback first

I have this code:
searchButton.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
statusLabel.setText("Searching...");
final String query = searchField.getText();
RootPanel.get("flickr").clear();
AsyncCallback<Flickr> ac=new AsyncCallback<Flickr>(){
#Override
public void onFailure(Throwable caught) {
}
#Override
public void onSuccess(Flickr result) {
for(Photo p:result.getPhotos().getPhoto())
{
flck.add(p);
}
statusLabel.setText("");
}
};
mashupService.getFlickrPhotos(query, ac);
if(!flck.isEmpty())
{
for(int i=0;i<flck.size();i++)
{
RootPanel.get("flickr").add(new HTML("<img src='http://farm"+flck.get(i).getFarm()+".staticflickr.com/"+flck.get(i).getServer()+"/"+flck.get(i).getId()+"_"+flck.get(i).getSecret()+".jpg'/><br/>"));
}
}
}
});
I want execute first onSuccess (have flick.add)... but it executes after of if(!flck.isEmpty)... and I need have flck with data but I can't...
When I press secont time the same button, flck have data of first onClick...
Thanks in advance
Move the code inside the onSuccess() method that is depended on the result of AsyncCallback.
It's clear from the name that AsyncCallback is just like a AJAX request that talks to server asynchronously means the execution of code is not sequential.
Just move if(!flck.isEmpty)... inside onSuccess() method.

How can i get the edited proxy from RequestFactoryEditorDriver

I can't figure out how to update my celltable after changes have been made using an editor. If I could get the edited proxy then I can use the dataprovider to update my celltable.
public void saveCampaign() {
driver.flush();
// the problem. proxy at this point should have the new values?....
context.persist().using(proxy).fire(new Receiver<Void>() {
#Override
public void onSuccess(Void response) {
showListView();
}
});
}
The proxy in .using(proxy) does not contain the changes made on the editor. However the persist method on the server gets the updated values. If I reload the data from the server I get the correct values to the celltable.
public void editCampaign(CampaignProxy proxy) {
this.proxy = proxy;
if (proxy != null) {
context = AEHOME.requestFactory.campaignRequest();
showEditView();
}
}
private void showEditView() {
driver.initialize(eventBus, AEHOME.requestFactory, editView);
driver.edit(proxy, context);
deckPanel.showWidget(deckPanel.getWidgetIndex(editView));
}
Proxy is set in the list view: configurationPageView.proxy = selectionModel.getSelectedObject();
Any advice would be greatly appreciated. Thank you.
You can change how the request is built by doing the following:
private void showEditView() {
driver.initialize(eventBus, AEHOME.requestFactory, editView);
driver.edit(proxy, context);
// Set up method invocation and callback in advance
context.persist().using(proxy).to(new Receiver<Void>() {
#Override
public void onSuccess(Void response) {
showListView();
}
}););
deckPanel.showWidget(deckPanel.getWidgetIndex(editView));
}
public void saveCampaign() {
driver.flush().fire();
}
In GWT 2.4 it will be possible to keep your current code organization and use RequestContext.append():
public void saveCampaign() {
// Returns the context passed to edit()
RequestContext ctx = driver.flush();
// append() is generic and returns the type returned by myProxyContext();
ctx.append(requestFactory.myProxyContext()).persist().using(proxy).fire(....);
}

How to prevent DoubleSubmit in a GWT application?

To clarify what double submit is: When the user clicks on a submit button twice, the server will process the same POST data twice. To avoid this (apart from disabling the button after a single submit), most web frameworks like Struts provide a token mechanism. I am searching for the equivalent of this in GWT.
If you want to avoid submitting twice, how about:
boolean processing = false;
button.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
if (!processing) {
processing = true;
button.setEnabled(false);
// makes an RPC call, does something you only want to do once.
processRequest(new AsyncCallback<String>() {
#Override
public void onSuccess(String result) {
// do stuff
processing = false;
button.setEnabled(true);
});
});
}
}
});
That's the gist of it.
This will be helpfull for you -
final Button btn = new Button("Open");
btn.addSelectionListener(new SelectionListener<ButtonEvent>() {
#Override
public void componentSelected(ButtonEvent ce) {
btn.setEnabled(false);
openMethod(name, new AsyncCallback<Void>() {
public void onFailure(Throwable caught) {
btn.setEnabled(true);
}
public void onSuccess(Void result) {
MessageBox.alert(info, "Opened Window", null);
btn.setEnabled(true);
window.hide();
}
});
}
});