0

There is a Vaadin 23 tutorial which shows how to send messages to all users (broadcast) https://vaadin.com/docs/latest/advanced/server-push But what if I need to send a Push message from me to only one other specific user? Is it possible with server push and Vaadin and if so - how ? For example, an Admin user updated something for another User and would like to immediately notify such user about that.

UPDATED

Based on the answer and comments, I updated the Broadcaster from the example to the following:

public class Broadcaster {

    static Executor executor = Executors.newSingleThreadExecutor();

    static Map<String, List<Consumer<String>>> listeners = new ConcurrentHashMap<>();

    public static synchronized Registration register(String userUuid, Consumer<String> listener) {
        addListener(userUuid, listener);

        return () -> {
            synchronized (Broadcaster.class) {
                listeners.remove(listener);
            }
        };
    }

    private static synchronized void addListener(String userUuid, Consumer<String> listener) {
        List<Consumer<String>> consumers = listeners.get(userUuid);
        if (consumers == null) {
            consumers = new LinkedList<>();
        }
        consumers.add(listener);
        listeners.put(userUuid, consumers);
    }

    public static synchronized void broadcast(String userUuid, String message) {

        List<Consumer<String>> consumers = listeners.get(userUuid);

        if (CollectionUtils.isNotEmpty(consumers)) {
            for (Consumer<String> consumer : consumers) {
                executor.execute(() -> consumer.accept(message));
            }
        }
    }

}

Will such implementation properly work in case I'd like to push a message to the listeners of the specific user?

alexanoid
  • 24,051
  • 54
  • 210
  • 410

1 Answers1

1

You need some PubSub in place. Push is pretty much agnostic to distribution events or what you do with it in general. It just allows the server to notify the client-side out-of-band. What means you use this features for, is up to you.

E.g. each client could register to the pub-sub on session-init with their user-name or -group (or a subject in general) and later some admin publishes notifications with the target. Only clients registered to that target react by e.g. pushing.

The poor-mans version would be all clients listening to the same stream of messages but only react if they are mentioned as the target. This is most likely less efficient.

cfrick
  • 35,203
  • 6
  • 56
  • 68
  • Thanks for your answer! Could you please show an example of how to register with a specific user-name in Vaadin in order to avoid the poor-man version with broadcast? – alexanoid Sep 25 '22 at 16:41
  • 1
    For the "vaadin part" there is no(t much) difference to what your linked example shows: pick a good place to hook your bus up with your users UI. For the distribution part _you_ have to make an architectural choice. You already have something in place, like Spring? Use it. You only have three users? Maybe poor-mans-version isn't that bad after all. You want to notify other applications? Maybe you need something full-blown like rabbitMQ. – cfrick Sep 25 '22 at 17:07
  • I'm just trying to understand - there is no way to notify only one single client? all clients registered with for example `UI ui = attachEvent.getUI(); broadcasterRegistration = Broadcaster.register(newMessage -> { ui.access(() -> messages.add(new Span(newMessage))); });` will receive the same message and will decide to react on it or not ? – alexanoid Sep 25 '22 at 17:15
  • 1
    If you want to expand from the linked example, you can start by replacing the "message", which is a String, with an object, that holds the user and the message. The sender now creates a message for either all or a specific user; the recipients have to check, if the message was for all or themself. This makes "trust" in your clients mandatory, if you send sensitive messages... but since you write all the code in one application, that should be a given. – cfrick Sep 25 '22 at 17:23
  • Thanks, maybe I didn't get it correctly but right now looks like even in case I'll add the userId into the message - each particular message will be delivered to and evaluated by every single client registered to this channel? And only based on the userId check, the client will decide to process it or not? – alexanoid Sep 25 '22 at 17:31
  • 1
    Yes, this is what I said in the last comments. If you don't want that, you have to move the filtering into the "broadcaster"-part of the example. Subscribers register for a topic and the bus only notifiies subscribers matching that topic.. – cfrick Sep 25 '22 at 17:47
  • 1
    Put in different words, you could have one broadcaster per user (in the simple case, that could be a global userId -> broadcaster map) instead of only a single broadcaster that is subscribed to by all users. – Leif Åstrand Sep 25 '22 at 19:47
  • Thanks! I updated my question with a modified Broadcaster example. Could you please confirm that such implementation must work, and I'm on the right/safe way in order to implement it? – alexanoid Sep 25 '22 at 20:25
  • I already implemented it, works great! It looks like a pure magic!) Thank you very much for your help !!! Please correct me if I'm wrong - the only way to scale such type of application is to use sticky sessions? – alexanoid Sep 25 '22 at 21:42