MyTetra Share
Делитесь знаниями!
Перехват события ApplicationEvent
Время создания: 28.01.2021 13:48
Раздел: INFO - Development - CUBA
Запись: wwwlir/Tetra/master/base/1611812936d92kt78r8y/text.html на raw.githubusercontent.com

Перехват события ApplicationEvent

Вопросы и проблемы

deployment

Yernar Adilbekovshut.desert

дек. 2017

Добрый день!
Задача такая, есть некий сервис в котором есть метод sentMessage.
Метод sendMessage публикует событие
MsgEvent через Events (в версии 6.7).
Нужно перехватить это событие в ExtAppMainWindow и вывести.

Проблема: я отправляю событие через Events, но в перехватчик в ExtAppMainWindow ничего не приходит.
Перехватывающий метод имеет аннотацию @EventListener

Если тип события MsgEvent наследовать от UiEvent, то его уже я не увижу в сервисе. А он мне нужен именно в сервисе…

Если вы опубликовали событие при помощи Events и оно не реализует интерфейс UiEvent, то ничего никуда прийти не должно было, только если вы не передали событие ещё как-то.

ссылки

Частые авторы

9

6

Популярные ссылки

22

https://youtrack.cuba-platform.com/issue/PL-9024

13

GitHub - cuba-labs/demo-broadcast-event github.com

15 ответов с предполагаемым временем прочтения около 5 минут.

Юрий АртамоновartamonovЛидер

дек. 2017

События в UI полностью отделены от глобальных событий, вам потребуется самостоятельно регистрировать слушатели UI в глобальном компоненте-бине.

Например:

Copy

@Component

public class MessageEventBroadcaster {

public final List<WeakReference<Consumer<GlobalMessageEvent>>> subscriptions = new ArrayList<>();


@EventListener

protected void onMessage(GlobalMessageEvent event) {

synchronized (subscriptions) {

Iterator<WeakReference<Consumer<GlobalMessageEvent>>> iterator = subscriptions.iterator();

while (iterator.hasNext()) {

WeakReference<Consumer<GlobalMessageEvent>> reference = iterator.next();

Consumer<GlobalMessageEvent> eventConsumer = reference.get();

if (eventConsumer == null) {

iterator.remove();

} else {

eventConsumer.accept(event);

}

}

}

}


public void subscribe(Consumer<GlobalMessageEvent> handler) {

synchronized (subscriptions) {

subscriptions.add(new WeakReference<>(handler));

}

}

}


Это компонент, который хранит список подписок в виде слабых ссылок. Это нужно, чтобы не порождать утечки памяти.

В расширенном главном окне, мы подписываемся на рассылку события:

Copy

public class ExtAppMainWindow extends AppMainWindow {

@Inject

private MessageEventBroadcaster broadcaster;


@Inject

private BackgroundWorker backgroundWorker;


private Consumer<GlobalMessageEvent> messageHandler;


@Override

public void init(Map<String, Object> params) {

super.init(params);


UIAccessor uiAccessor = backgroundWorker.getUIAccessor();

// save reference to message handler

messageHandler = event -> uiAccessor.access(() -> {

showNotification(event.getMessage());

});


broadcaster.subscribe(messageHandler);

}


Здесь мы создаём подписку на рассылку и обеспечиваем доступ к состоянию UI при помощи UIAccessor. Это необходимо, поскольку рассылка выполняется из другого потока. Из блока access { } мы можем изменять состояние UI, например, показывать нотификации.

Разослать событие можно при помощи бина Events:

Copy

@Inject

private Events events;


public void onSendBtnClick() {

events.publish(new GlobalMessageEvent("Demo for all!"));

}


Я подготовил небольшой пример: https://github.com/cuba-labs/demo-broadcast-event 13

Обратите внимание, что в этом примере бин и экраны находятся в одном приложении - Web Client. Этот способ не подходит для отправки событий из core в Web Client.

Yernar Adilbekovshut.desert

дек. 2017

Отлично! Как можно отправить некое событие в виде Notification всем пользователям которые онлайн в системе или отправить только одному (по логину)

Yernar Adilbekovshut.desert

дек. 2017

Я так понимаю, это уже через сокет решается?

Юрий АртамоновartamonovЛидер

дек. 2017

Обработчик сработает у всех экземпляров ExtAppMainWindow, нужно будет в нём отфильтровать по текущему пользователю события, например добавив в сообщение поле “получатель”. Это всего лишь пример рассылки сообщений всем HTTP сессиям / открытым вкладкам браузера. Кроме того, здесь сейчас никак не обрабатываются ошибки, которые могут возникнуть.

Юрий АртамоновartamonovЛидер

shut.desert

дек. 2017

Вызов ui.access() автоматически доставит изменения в браузер пользователя по WebSocket соединению, это не нужно реализовывать

Yernar Adilbekovshut.desert

дек. 2017

Спасибо большое, все работает!

20 дней спустя

Yernar Adilbekovshut.desert

дек. 2017

Можно ли как то событие перекинуть с core или global слоя на веб слой?

Konstantin KrivopustovkrivopustovCUBA.platform

янв. 2018

Пока “из коробки” такого способа нет. Есть тикет: https://youtrack.cuba-platform.com/issue/PL-9024 22

8 дней спустя

Yernar Adilbekovshut.desert

1

янв. 2018

Подскажите пожалуйста, что то путаница в голове…
Если в ExtAppMainWindow создать метод

Copy

@EventListener

private void messgeHandle(GlobalMessageEvent e){}


То я ведь так же могу иметь доступ к ExtAppMainWindow и вызвать showNotification?

Есть ли нужда создавать MessageEventBroadcaster?

Юрий АртамоновartamonovЛидер

янв. 2018

Да, вы можете в этом методе использовать showNotification, но глобальные события, опубликованные из бинов, не будут приходить в этот метод, пока вы сами их туда не отправите, как показано в примере с MessageEventBroadcaster.

Yernar Adilbekovshut.desert

янв. 2018

Если c какого либо контроллера страницы или с бина который находится в веб модуле, отправить событие GlobalMessageEvent, то все методы объявленные с аннотацией @EventListener(GlobalMessageEvent.class) в модуле web, получат это событие! Не так ведь? Объясните пожалуйста, запутался что то?) Или я что то не учитываю и ошибаюсь?

Юрий АртамоновartamonovЛидер

янв. 2018

Объекты экранов UI не являются бинами и хранятся в пользовательских сессиях. Поэтому для обработчиков событий в них это не выполняется. События обрабатываются в экранах UI, только если порождены в экранах / в рамках пользовательской сессии и реализуют интерфейс UiEvent.

Yernar Adilbekovshut.desert

янв. 2018

Ясно, спасибо! У меня получилось так, создал GlobalMessageEvent который наследует только ApplicationEvent. Написал @EventListener метод для GlobalMessageEvent в ExtAppMainWindow. И опубликовал это событие в TestEdit(стандартная форма редактирования сущности Test), и вуаля уведомление перехватил в ExtAppMainWindow. Это правильная реализация перехвата уведомлении?

Юрий АртамоновartamonovЛидер

янв. 2018

Если вы опубликовали событие при помощи Events и оно не реализует интерфейс UiEvent, то ничего никуда прийти не должно было, только если вы не передали событие ещё как-то.

Вопрос решён


 
MyTetra Share v.0.55
Яндекс индекс цитирования