Loading...
Important Notice - Forums is archived

To simplify things and help our users to be more productive, we have archived the current forum and focus our efforts on helping developers on Stack Overflow. You can post new questions on Stack Overflow or join our Discord channel.

Product icon
TUTORIAL

Vaadin lets you build secure, UX-first PWAs entirely in Java.
Free ebook & tutorial.

Vaadin CDI: @UIScoped / @Observes & javax.inject.Provider

J F
6 years ago Sep 22, 2015 7:43pm
Peter Lehto
6 years ago Sep 24, 2015 8:07pm

Hey buddy, I'm not exactly sure if I understand what you tried to achieve but I'll try to give few pointers and hope they help.

javax.enterprise.event.Event is related to the currently active scopes / context in such a way that if you fire an event from ViewScoped, UIScoped or SessionScoped beans the event can only be observed in those beans which share the same or higher scope within the same context. This is, if from ViewScoped you fire an event it can only be observed in other ViewScoped, UIScoped, SessionScoped or ApplicationScoped beans belonging to the same context. With context I mean "user session". This effectively means that you cannot fire an event from UI to UI.

The javax.inject.Provider that you're referring to is a way to programatically inject a bean. It's especially handy if you want to inject the bean inside your code instead of injecting it with a static injection point by using @Inject. Provider behaves same way as other injections in general which means that if you attempt to inject bean which is UIScoped the actual injected bean will always be the same as long as you're "inside" the same UI.

Your problem for making the chat application is in general that CDI events cannot target beans in "sibling scopes" which don't share a context. This simply means that you cannot fire an event from one UI to another. What you can do on the other hand is that you make a "global" component which is for example in @ApplicationScope. This bean is shared between all the other beans belonging to same CDI deployment. What you could do there is that you have a collection or map of available UI's participating to the chat session and when you detect that an event targets one of these UI's you would call ui.access(Runnable) for that particular UI. Calling UI.access will activate the context of the particular UI allowing it to work as part of the process.

In short, I would advice the following:

1) ViewScope -> UIScope -> SessionScope -> ApplicationScope is the only way how events propagate but even then they cannot cross context boundary from one user session to another user session or from one ui scoped bean to another ui scoped bean (if those ui scoped beans belong to different UI's, which are in different contexts)

2) Events cannot propagate between sibling beans meaning that you cannot fire an event from UI to UI.

3) To make a chat application you need to have a component in your system that acts as singleton @ApplicationScoped. This component can receive events with @Observes from all other beans as its effectively part of everybody elses context as well.

4) The @ApplicationScoped component needs to maintain information about other UI's participating the chat and it needs to access the particular recipient UI with UI.access(Runnable) method. Inside the runnable you provide the actual logic that you want to execute when event is propagated. This takes care of activating the proper context as well as thread safety.

5) Provider is just a programmatic way to inject the bean instead of using static @Inject based injection point. It will follow the same scoping rules as other injections as well, hence if inside a UI- or ViewScoped bean you attempt to inject the UI you will always get the same instance.

Hope the above thoughts help!

cheers,
Peter

Peter Lehto
6 years ago Sep 24, 2015 8:18pm

I drew a little illustration on how scoping works.

https://drive.google.com/file/d/0B7BydXnTdb0vTHpIbFVra19PTVE

Idea would be that in higher level bean you have a reference to the head of "other user's stack".

In world of Spring there is  a global event bus called ApplicationEvents, I don't think CDI has equivalent for that unfortunately.

J F
6 years ago Sep 28, 2015 6:48pm