On GWTP I am sending a UpdateDiagramBoxEvent with the code below, but the handler is executed twice. In other words, I can see that the sendUpdateDiagramBoxEvent() is executed only once, but it is received twice. The same is happening with many other events on my code. Any ideas of what is wrong, and how can I avoid this behaviour? THANKS.
Receive event
UpdateDiagramBoxHandler updateDiagramBoxHandler = new UpdateDiagramBoxHandler() {
#Override
public void onUpdateDiagramBox(UpdateDiagramBoxEvent event) {
doSomething();
}
};
Send event
EventUtil.sendUpdateDiagramBoxEvent(CellTableManager.this.eventBus,
BasicConstants.EventSubscriptors.VIEW, 0,
BasicConstants.EditableTableFields.DIAGRAMTYPE,
ClientState.getCurrentDiagramType().name());
public static void sendUpdateDiagramBoxEvent(final EventBus eventBus,
final BasicConstants.EventSubscriptors recipient,
final int index, final BasicConstants.EditableTableFields field,
final String value){
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
#Override
public void execute() {
UpdateDiagramBoxEvent updateDiagramBoxEvent =
new UpdateDiagramBoxEvent(transactionNumber, recipient,
field.toString(), value, index);
eventBus.fireEvent(updateDiagramBoxEvent);
}
});
}
Register event handler (from MyProjectPresenter.java)
#Inject PlaceManager placeManager;
#Override
protected void onBind() {
[...]
registerHandler(getEventBus().addHandler(UpdateDiagramBoxEvent.getType(),
updateDiagramBoxHandler));
}
It generally means that you simply registered your event handlers twice.
Is this GWTP and if so how are you registering your events/handlers? I seem to recall there is a pitfall that you can use either #ProxyEvent or addRegisteredHandler() but not both, or you will receive the events twice.
Hope that helps.
Cheers,
Or the bean in question might not be singleton.
Related
I have been trying to create an async listener that would execute after my request has been terminated which mean my transaction has been committed. Unfortunately i was not able to make it happen it is always part of the main thread. Which mean my request would never END before the async methods is finishing. It is basically for creating a webhook service that would send an http request when the request going through my system end and the transaction is committed. Does anyone had a similar issue ?
#Component
#RequiredArgsConstructor
public class EventListenerAsync {
#PostPersist
public void postPersist(final Event event) {
TransactionSynchronizationManager.registerSynchronization(
new TransactionSynchronization() {
#Override
public void afterCompletion(final int status) {
if (status == TransactionSynchronization.STATUS_COMMITTED) {
// call #async public method from another class
}
}
});
}
#TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void processEventAsynce(final Event event) {
// call #async public method from another class
}
}
Thanks a lot for you help.
I am running RxJava and creating a subject to use onNext() method to produce data. I am using Spring.
This is my setup:
#Component
public class SubjectObserver {
private SerializedSubject<SomeObj, SomeObj> safeSource;
public SubjectObserver() {
safeSource = PublishSubject.<SomeObj>create().toSerialized();
**safeSource.subscribeOn(<my taskthreadExecutor>);**
**safeSource.observeOn(<my taskthreadExecutor>);**
safeSource.subscribe(new Subscriber<AsyncRemoteRequest>() {
#Override
public void onNext(AsyncRemoteRequest asyncRemoteRequest) {
LOGGER.debug("{} invoked.", Thread.currentThread().getName());
doSomething();
}
}
}
public void publish(SomeObj myObj) {
safeSource.onNext(myObj);
}
}
The way new data is generated on the RxJava stream is by #Autowire private SubjectObserver subjectObserver
and then calling subjectObserver.publish(newDataObjGenerated)
No matter what I specify for subscribeOn() & observeOn():
Schedulers.io()
Schedulers.computation()
my threads
Schedulers.newThread
The onNext() and the actual work inside it is done on the same thread that actually calls the onNext() on the subject to generate/produce data.
Is this correct? If so, what am I missing? I was expecting the doSomething() to be done on a different thread.
Update
In my calling class, if I change the way I am invoking the publish method, then of course a new thread is allocated for the subscriber to run on.
taskExecutor.execute(() -> subjectObserver.publish(newlyGeneratedObj));
Thanks,
Each operator on Observable/Subject return a new instance with the extra behavior, however, your code just applies the subscribeOn and observeOn then throws away whatever they produced and subscribes to the raw Subject. You should chain the method calls and then subscribe:
safeSource = PublishSubject.<AsyncRemoteRequest>create().toSerialized();
safeSource
.subscribeOn(<my taskthreadExecutor>)
.observeOn(<my taskthreadExecutor>)
.subscribe(new Subscriber<AsyncRemoteRequest>() {
#Override
public void onNext(AsyncRemoteRequest asyncRemoteRequest) {
LOGGER.debug("{} invoked.", Thread.currentThread().getName());
doSomething();
}
});
Note that subscribeOn has no practical effect on a PublishSubject because there is no subscription side-effect happening in its subscribe() method.
I have an application that uses EventBus for dispatching Application wide events. For some reason if I call one event and then try to register handler immediately before firing the second event it does not get dispatched. Is there any other way to dynamically register handlers on event ? Please see the code below:
MyEntry.java
package com.example.eventbus.client;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.event.shared.SimpleEventBus;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
public class MyEntry
implements EntryPoint {
SimpleEventBus bus;
#Override
public void onModuleLoad() {
bus = new SimpleEventBus();
fireEvent1();
}
private void fireEvent1(){
bus.addHandler(MyEvent1.TYPE,new MyEvent1.Handler() {
#Override
public void onEvent1(MyEvent1 event) {
RootPanel.get().add(new Label("Event1"));
fireEvent2();
}
});
bus.fireEvent(new MyEvent1());
}
private void fireEvent2(){
bus.addHandler(MyEvent2.TYPE,new MyEvent2.Handler() {
#Override
public void onEvent2(MyEvent2 event) {
RootPanel.get().add(new Label("Event2")); //!!!!!This line is not being called
}
});
bus.fireEvent(new MyEvent2());
}
}
MyEvent1.java
package com.example.eventbus.client;
import com.google.gwt.event.shared.EventHandler;
import com.google.gwt.event.shared.GwtEvent;
public class MyEvent1 extends GwtEvent<MyEvent1.Handler>{
public static Type<MyEvent1.Handler> TYPE=new Type<MyEvent1.Handler>();
#Override
public com.google.gwt.event.shared.GwtEvent.Type<Handler> getAssociatedType() {
return TYPE;
}
#Override
protected void dispatch(Handler handler) {
System.out.println("dispatch Event1");
handler.onEvent1(this);
}
public interface Handler extends EventHandler{
public void onEvent1(MyEvent1 event);
}
}
MyEvent2.java
package com.example.eventbus.client;
import com.google.gwt.event.shared.EventHandler;
import com.google.gwt.event.shared.GwtEvent;
public class MyEvent2 extends GwtEvent<MyEvent2.Handler>{
public static Type<MyEvent2.Handler> TYPE=new Type<MyEvent2.Handler>();
#Override
public com.google.gwt.event.shared.GwtEvent.Type<Handler> getAssociatedType() {
return TYPE;
}
#Override
protected void dispatch(Handler handler) {
System.out.println("dispatch Event2"); //!!!! This line is never called
handler.onEvent2(this);
}
public interface Handler extends EventHandler{
public void onEvent2(MyEvent2 event);
}
}
The issue is that while an event bus is firing events, it queues up any added or removed handler, and deals with them when it is finished. The idea is that if you only start listening to something while another event is still going off, then you are not interested for this round of events, but for the next round. The same thing happens when removing a handler - you will still hear about events that are still in the process of happening, but after the event bus is finished firing, it will deal with removal.
Try changing your code to wire up both handlers before firing anything, then try firing one event to the other.
Let me suggest to take a try to a new feature in gwtquery called 'custom events'.
We have introduced the new events mechanism during the recent GWT.create conferences, take a look to this slide (use arrows to move between slides).
You can attach custom events to any element in the DOM tree, widgets, and the window element.
Then you can trigger the event from any point in your code and every handler with this custom event name will be executed.
The main goal of the gQuery approach apart from being simpler, is that it performs significantly better than gwt eventbus, since the native browser selects in a low-level way which handlers to execute instead of using javascript to loop over a list, and execute handlers sequentially.
You might want to check out GWTP #ProxyEvent:
So when should you use #ProxyEvent? Basically, you use it every time that an event should have the ability to “wake up” your presenter. That is, whenever the presenter should be notified of an event even before it is first instantiated.
Background Story:
I am developing a GWT application, using the standard MVP design pattern, and also using RPC to get data from my custom data handling servlet (does a lot behind the scenes). Anyway, my goal is to create a very simple custom caching mechanism, that stores the data returned from the RPC callback in a static cache POJO. (The callback also sends a custom event using the SimpleEventBus to all registered handlers.) Then when I request the data again, I'll check the cache before doing the RPC server call again. (And also send a custom event using the EventBus).
The Problem:
When I send the event from the RPC callback, everything works fine. The problem is when I send the event outside the RPC callback when I just send the cached object. For some reason this event doesn't make it to my registered handler. Here is some code:
public void callServer(final Object source)
{
if(cachedResponse != null)
{
System.err.println("Getting Response from Cache for: "+ source.getClass().getName());
//Does this actually fire the event?
eventBus.fireEventFromSource(new ResponseEvent(cachedResponse),source);
}
else
{
System.err.println("Getting Response from Server for: "+ source.getClass().getName());
service.callServer(new AsyncCallback<String>(){
#Override
public void onFailure(Throwable caught) {
System.err.println("RPC Call Failed.");
}
#Override
public void onSuccess(String result) {
cachedResponse = result;
eventBus.fireEventFromSource(new ResponseEvent(cachedResponse),source);
}
});
}
}
Now I have two Activities, HelloActivity and GoodbyeActivity (taken from: GWT MVP code)
They also print out messages when the handler is called. Anyway, this is the output I get from the logs: (Not correct)
Getting Response from Cache for: com.hellomvp.client.activity.HelloActivity
Response in GoodbyeActivity from: com.hellomvp.client.activity.HelloActivity
Getting Response from Cache for: com.hellomvp.client.activity.GoodbyeActivity
Response in HelloActivity from: com.hellomvp.client.activity.GoodbyeActivity
What I expect to get is this:
Getting Response from Cache for: com.hellomvp.client.activity.HelloActivity
Response in HelloActivity from: com.hellomvp.client.activity.HelloActivity
Getting Response from Cache for: com.hellomvp.client.activity.GoodbyeActivity
Response in GoodbyeActivity from: com.hellomvp.client.activity.GoodbyeActivity
And I will get this expected output if I change the above code to the following: (This is the entire file this time...)
package com.hellomvp.client;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.shared.EventBus;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.hellomvp.events.ResponseEvent;
public class RequestManager {
private EventBus eventBus;
private String cachedResponse;
private HelloServiceAsync service = GWT.create(HelloService.class);
public RequestManager(EventBus eventBus)
{
this.eventBus = eventBus;
}
public void callServer(final Object source)
{
if(cachedResponse != null)
{
System.err.println("Getting Response from Cache for: "+ source.getClass().getName());
service.doNothing(new AsyncCallback<Void>(){
#Override
public void onFailure(Throwable caught) {
System.err.println("RPC Call Failed.");
}
#Override
public void onSuccess(Void result) {
eventBus.fireEventFromSource(new ResponseEvent(cachedResponse),source);
}
});
}
else
{
System.err.println("Getting Response from Server for: "+ source.getClass().getName());
service.callServer(new AsyncCallback<String>(){
#Override
public void onFailure(Throwable caught) {
System.err.println("RPC Call Failed.");
}
#Override
public void onSuccess(String result) {
cachedResponse = result;
eventBus.fireEventFromSource(new ResponseEvent(cachedResponse),source);
}
});
}
}
}
So the point it out, the only change is that I created a new RPC call that does nothing, and send the event in its callback, with the cached data instead, and it causes the application to work as expected.
So the Question:
What am I doing wrong? I don't understand why 'eventBus.fireEvent(...)' Needs to be in an RPC Callback to work properly. I'm thinking this is a threading issue, but I have searched Google in vain for anything that would help.
I have an entire Eclipse project that showcases this issue that I'm having, it can be found at: Eclipse Problem Project Example
Edit: Please note that using eventBus.fireEventFromSource(...) is only being used for debugging purposes, since in my actual GWT Application I have more than one registered Handler for the events. So how do you use EventBus properly?
If I understand your problem correctly you are expecting calls to SimpleEventBus#fireEventFromSource to be routed only to the source object. This is not the case - the event bus will always fire events to all registered handlers. In general the goal of using an EventBus is to decouple the sources of events from their handlers - basing functionality on the source of an event runs counter to this goal.
To get the behavior you want pass an AsyncCallback to your caching RPC client instead of trying to use the EventBus concept in a way other than intended. This has the added benefit of alerting the Activity in question when the RPC call fails:
public class RequestManager {
private String cachedResponse = null;
private HelloServiceAsync service = GWT.create(HelloService.class);
public void callServer(final AsyncCallback<String> callback) {
if (cachedResponse != null) {
callback.onSuccess(cachedResponse);
} else {
service.callServer(new AsyncCallback<String>(){
#Override
public void onFailure(Throwable caught) {
callback.onFailure(caught);
}
#Override
public void onSuccess(String result) {
cachedResponse = result;
callback.onSuccess(cachedResponse);
}
});
}
}
}
And in the Activity:
clientFactory.getRequestManager().callServer(new AsyncCallback<String>() {
#Override
public void onFailure(Throwable caught) {
// Handle failure.
}
#Override
public void onSuccess(String result) {
helloView.showResponse(result);
}
});
I want to cancel an event for the following handlers. The sample-class below shows, what I try. Altough the keyevent is canceled for the textbox, the second handler is still called. the order of the handlers is correct. i can prove that Handler1 is called before Handler2. in this sample-class I could use a flag, but in my real class, the handlers and the textbox are seperated, so flags would be a problem. any ideas?
public class EventTestTextBox extends TextBox {
public static class Handler1 implements KeyUpHandler {
#Override
public void onKeyUp(KeyUpEvent event) {
if (event.isShiftKeyDown()) {
event.preventDefault();
event.stopPropagation();
((TextBox)event.getSource()).cancelKey();
}
}
}
public static class Handler2 implements KeyUpHandler {
#Override
public void onKeyUp(KeyUpEvent event) {
Window.alert("should not appear if shift-key is down.");
}
}
public EventTestTextBox() {
super.addKeyUpHandler(new Handler1());
super.addKeyUpHandler(new Handler2());
}
}
event.stopPropagation() cancels event bubbling, i.e. prevents handlers on parent elements to be triggered. It does not prevent handlers on the same element to receive the event.
I have exactly the same question as you. Did you manage to find a solution ?
I guess that the only solution would be to not register the event listener and let the handler1 dispatch (or not) to handler 2 instead.