Does vaadin-spring-addon-eventbus forget its listeners after a page refresh

Hi all,

I use the EventBus.UIEventBus mechanism from the vaadin-spring-eventbus add-on 14.0.0 for indicating state updates between separated components in my web application (Vaadin 14.4.4). The main view class is annoted with @Route(“”) and @PreserveOnRefresh. All components inside the application are annotated with @UIScope, so in general my application is ready for multi-tab use. Everything works fine so far.

In the following you can see, how an event is fired via UIEventBus. In the second line you see the callback of the onEvent() method in the listener:

2020-12-06 18:45:23,355 | DEBUG | 5EC9D1D25C | o.v.s.e.i.ScopedEventBus$DefaultUIEventBus | Publishing payload [UpdateEvent [commands=[SWITCH_TO_EMULATION]
]] from sender [eu.fhms.msb.mu0.web.view.HeaderView@4b101e12]
 on event bus [DefaultUIEventBus[id=620df8a2, eventScope=UI, parentEventBus=DefaultSessionEventBus[id=e1f01b8, eventScope=SESSION, parentEventBus=DefaultApplicationEventBus[id=4843fd0d, eventScope=APPLICATION, parentEventBus=null]
]]] in topic  []
2020-12-06 18:45:23,356 | TRACE | 5EC9D1D25C | e.f.m.mu0.web.view.HeaderView | onEvent: Event[scope=UI, eventBus=DefaultUIEventBus[id=620df8a2, eventScope=UI, parentEventBus=DefaultSessionEventBus[id=e1f01b8, eventScope=SESSION, parentEventBus=DefaultApplicationEventBus[id=4843fd0d, eventScope=APPLICATION, parentEventBus=null]
]], ts=1607276723355, source=[eu.fhms.msb.mu0.web.view.HeaderView@4b101e12]
, payload=[UpdateEvent [commands=[SWITCH_TO_EMULATION]
]]]

However, when I refresh the page in the browser, the components keep their states and still work, but with an important difference: the internal event bus “forgets” all its registered listeners. The missing events are a big problem:

2020-12-06 18:46:41,600 | DEBUG | 5EC9D1D25C | o.v.s.e.i.ScopedEventBus$DefaultUIEventBus | Publishing payload [UpdateEvent [commands=[SWITCH_TO_ASSEMBLER]
]] from sender [eu.fhms.msb.mu0.web.view.HeaderView@4b101e12]
 on event bus [DefaultUIEventBus[id=620df8a2, eventScope=UI, parentEventBus=DefaultSessionEventBus[id=e1f01b8, eventScope=SESSION, parentEventBus=DefaultApplicationEventBus[id=4843fd0d, eventScope=APPLICATION, parentEventBus=null]
]]] in topic  []
2020-12-06 18:46:41,601 | DEBUG | 5EC9D1D25C | o.v.s.e.i.ListenerCollection | No listeners supported event [Event[scope=UI, eventBus=DefaultUIEventBus[id=620df8a2, eventScope=UI, parentEventBus=DefaultSessionEventBus[id=e1f01b8, eventScope=SESSION, parentEventBus=DefaultApplicationEventBus[id=4843fd0d, eventScope=APPLICATION, parentEventBus=null]
]], ts=1607276801601, source=[eu.fhms.msb.mu0.web.view.HeaderView@4b101e12]
, payload=[UpdateEvent [commands=[SWITCH_TO_ASSEMBLER]
]]]]

I tried to re-subscribe the listeners in the onAttach() callback method, which is called after the refresh, but this doesn’t succeed:

  protected void onAttach(AttachEvent attachEvent) {
    uiEventBus.subscribe(this);
  }

Do you have any idea, what’s the problem?

Best regards,

Claus

Hi again,

I’ve made some progress on the solution: The subscribed listeners must unsubscribe on detach event and afterwards re-subscribe to UI event bus on attach event. Both events are fired during refreshing the page (no matter whether reload button is pressed or URL is re-entered).

 private @Autowired EventBus.UIEventBus uiEventBus;
 
 @Override
  protected void onAttach(AttachEvent attachEvent) {
    uiEventBus.subscribe(this);
  }
  
  @Override
  protected void onDetach(DetachEvent detachEvent) {
    uiEventBus.unsubscribe(this);
  }
  
  @EventBusListenerMethod
  protected void onEvent(Event<UpdateEvent> e) {

    logger.trace("onEvent: {}", e);
	...
  }

By this, the then fired events are transmitted via event bus - but only when you refresh the page at least twice or more times. In case of a single refresh, the re-subscribed listeners are not found.

2020-12-07 19:31:39,668 | DEBUG | 4123DAE4EE | o.v.s.e.i.ListenerCollection | No listeners supported event ...

I have no idea why.

Best regards,

Claus

Hi again,

I’m still looking for a solution. I’ve built a small demo project (you find the Eclipse project as an attachment). The MainView contains a split pane.

  • On the left side a button is waiting for clicks. Each click is published via autowired UI event bus.
  • The right side contains a VerticalLayout that has subscribed to the autowired UI event bus. The RightView class offers a listener method by annotation
 @EventBusListenerMethod
  protected void onEvent(Event<String> e) {
    logger.trace("onEvent: {}", e);

    add(new Label(e.getPayload()));  // each click adds a label to the right pane
  }

Everything works fine until you refresh the @PreserveOnRefresh-annotated view. All visible elements and text fields are preserved (as expected), but the internal event bus isn’t. You see the following destroy message in the log file:

19:45:57.654 [http-nio-8080-exec-1]
 TRACE o.v.s.e.i.ScopedEventBus$DefaultUIEventBus - Destroying event bus [DefaultUIEventBus[id=44cbc7b, eventScope=UI, parentEventBus=DefaultSessionEventBus[id=6396d126, eventScope=SESSION, parentEventBus=DefaultApplicationEventBus[id=78c42394, eventScope=APPLICATION, parentEventBus=null]
]]] and removing all listeners
19:45:57.655 [http-nio-8080-exec-1]
 TRACE o.v.s.e.i.ScopedEventBus$DefaultSessionEventBus - Unsubscribing listener [org.vaadin.spring.events.internal.ScopedEventBus$1@6f0b4227]
 from event bus [DefaultSessionEventBus[id=6396d126, eventScope=SESSION, parentEventBus=DefaultApplicationEventBus[id=78c42394, eventScope=APPLICATION, parentEventBus=null]
]]
19:45:57.656 [http-nio-8080-exec-1]
 TRACE o.v.s.e.internal.ListenerCollection - Removing listener [org.vaadin.spring.events.internal.EventBusListenerWrapper@1b68b1ee]

Pressing the button again has no effect (as expected), the event bus has lost its listeners:

19:46:21.439 [http-nio-8080-exec-7]
 DEBUG o.v.s.e.i.ScopedEventBus$DefaultUIEventBus - Publishing payload [clicked @ 2020-12-18T19:46:21.439849100]
 from sender [com.example.application.views.LeftView@7e44656f]
 on event bus [DefaultUIEventBus[id=44cbc7b, eventScope=UI, parentEventBus=DefaultSessionEventBus[id=6396d126, eventScope=SESSION, parentEventBus=DefaultApplicationEventBus[id=78c42394, eventScope=APPLICATION, parentEventBus=null]
]]] in topic  []
19:46:21.440 [http-nio-8080-exec-7]
 DEBUG o.v.s.e.internal.ListenerCollection - No listeners supported event [Event[scope=UI, eventBus=DefaultUIEventBus[id=44cbc7b, eventScope=UI, parentEventBus=DefaultSessionEventBus[id=6396d126, eventScope=SESSION, parentEventBus=DefaultApplicationEventBus[id=78c42394, eventScope=APPLICATION, parentEventBus=null]
]], ts=1608317181439, source=[com.example.application.views.LeftView@7e44656f]
, payload=[clicked @ 2020-12-18T19:46:21.439849100]
]]

Okay, now it’s time for plan B. We unsubscribe the listener in the onDetach() method and re-subscribe it in the onAttach() method. Nice idea, but it does not work. The attachment happens BEFORE the event bus destroys its internal list. The freshly re-suscribed listeners are removed again.

And now it’s getting funny. The destruction of the event listener list happens only for the first page refresh. We never see

19:45:57.654 [http-nio-8080-exec-1]
 TRACE o.v.s.e.i.ScopedEventBus$DefaultUIEventBus - Destroying event bus [DefaultUIEventBus[id=44cbc7b, eventScope=UI, parentEventBus=DefaultSessionEventBus[id=6396d126, eventScope=SESSION, parentEventBus=DefaultApplicationEventBus[id=78c42394, eventScope=APPLICATION, parentEventBus=null]
]]] and removing all listeners

for the second or any later refresh. So, un- and re-subscribing works well, but not for the first page refresh.

My questions:

  • How can I persuade the EventBus to preserve the list of registered listeners?
  • And why the internal method ScopedEventBus.destroy() is called exactly once, even though the page is refreshed multiple?

Best regards,

Claus

Small demo project and screenshot
18499111.zip (141 KB)
18499114.png