Прослушивание и обработка событий

Этот раздел объясняет, как программным образом составить список событий контекста, подписаться на него и обработать.

Выяснение доступных событий

Существует несколько способов получения списка событий из Context:

  • getEventDefinitions() - этот метод вернет список всех событий в контексте
  • getEventDefinitions(CallerController caller) - этот метод вернет список событий, доступных вызывающему
  • getEventDefinitions(String group) - этот метод вернет список событий, принадлежащих определенной группе его подгрупп
  • getEventDefinitions(CallerController caller, String group) -  этот метод вернет список событий, принадлежащих определенной группе и доступных вызывающему

List<EventDefinition> events = context.getEventDefinitions(ContextUtils.GROUP_REMOTE); // Finding all events in group "remote"

Для извлечения одного определения события по его имени вызовите метод getEventDefinition(String name). Метод getEventDefinition(String name, CallerController caller) вернет определение или ноль, если событие недоступно вызывающему.

Инициирование событий

Как только определенный компонент системы (например, драйвер устройства) определяет, что что-то произошло, он может инициировать событие контекста. Событие может быть запущено асинхронно из любого потока. Имейте в виду, что не существует общего способа удаленного запуска события (из SberMobile IIoT Platform Client или используя SberMobile Server API).

Для запуска события вызовите метод Context.fireEvent(). Этот метод принимает следующие параметры:

  • Имя события
  • Уровень события
  • Параметры события (в форме встроенной DataTable или списка значений ее ячеек)

Пример 1: запуск события путем подачи события DataTable:

DataTable eventData = new SimpleDataTable(context.getEventDefinition("myEvent").getFormat()); // Creating empty value

 

eventData.addRecord().addString("str1").addInt(111); // Adding a record

 

context.fireEvent("myEvent", EventLevel.INFO, eventData);

Пример 2: запуск события путем подачи значения ячейки таблицы событий:

context.fireEvent("randomValue", EventLevel.INFO, new Float(Math.random() * 1000000));

Подписка на события

Модули сервера могут подписываться на события контекста, чтобы получать и обрабатывать их экземпляры. В большинстве случаев эта функциональность требуется при реализации настраиваемых плагинов сервера.

Чтобы подписаться на событие, нужно:

  • Создать экземпляр класса, реализующего интерфейс ContextEventListener
  • Передать этот экземпляр методу Context.addEventListener()

Интерфейс ContextEventListener имеет множество методов, и в большинстве случаев разумнее наследовать слушателя вашего события из существующей реализации:

  • При написании кода сервера (например, плагина) наследуйте слушателя вашего события из ServerEventListener для обеспечения правильного уровня прав доступа.
  • В других случаях используйте DefaultContextEventListener в качестве базы.

Использование DefaultContextEventListener из кода, запущенного на сервере виртуальной машины Java, приведет к отсутствию получения каких-либо событий. Это происходит из-за того, что слушатель по умолчанию не получает необходимый уровень прав доступа.

Массовая подписка путем менеджера контекстов

Также возможно подписаться на события путем void addMaskEventListener(String mask, String event, ContextEventListener listener) метода ContextManager. У этого пути прдписки есть большое количество различий от подписки путем интерфейса Context:

  • Возможно получать события от различных ресурсов, указывая маску контекстов
  • Если подписка была сделана путем ContextManager, определенный контекст был удален, a новый был создан с таким же именем, тот же самый слушатель будет автоматически добавлен в новый контекст

Слабые слушатели

У большинства методов подписки есть подписи, которые принимают флажок boolean weak. Если определенный пользователь добавлен в качестве слабого, подписчик автоматически будет сборщиком мусора, если нет сильных ссылок на это.

Все слушатели по умолчанию не являются слабыми.

Обработка событий

Как только вы подписались на событие путем добавления слушателя, система будет вызывать метод слушателя handle() каждый раз, когда происходит событие. Таким образом, вся логика обработки должна добавляться к реализации этого метода:

DefaultContextEventListener listener = new DefaultContextEventListener()

{

  @Override

  public void handle(Event event) throws EventHandlingException

    {

       // Handling event here

                 

       int level = event.getLevel();

          

       List<Acknowledgement> acknowledgements = event.getAcknowledgements();

       

       // Accessing event data

       DataTable eventData = event.getData();

    }

};

      

context.addEventListener("eventName", listener);

Получение доступа к историческим событиям

Существует два способа получить доступ к историческим событиям, хранящимся в базе данных сервера:

  • Вызвать функцию получить из контекста события. Этот метод сработает как локально (внутри драйверов/плагинов сервера), так и удаленно (через сервер API).
  • Вызвать метод Java Server.getDaoFactory().getEventDao().getEvents(). Этот способ чуть быстрее, чем предыдущий, но он работает только внутри сервера виртуальной машины Java (т.е. в драйверах/плагинах).

Вызов функции get

Функция get контекста События возвращает таблицу данных, каждая строка которой содержит информацию об одном историческом событии. См. ее описание здесь.

DataTable history = eventsContext.callFunction(EventsContextConstants.F_GET, getCallerController(), con.getPath(), vd.getName()); // Other parameters omitted

 

for (DataRecord rec : history)

{

  // Process historical events

}

Использование прямого доступа к базе данных

Метод класса EventDao, выполняющий загрузку событий из базы данных, имеет следующую сигнатуру:

public Iterator<Event> getEvents(ContextManager cm, CallerController caller, EntityList eventList, EventsFilter filter, Date startDate, Date endDate, Integer maxResults, String sortBy,

      boolean sortAscending, Object... additionalCriteria) throws DaoException;

Этот метод принимает список типов событий для загрузки, предварительной фильтрации (additionalCriteria) и постфильтрации (filter), даты начала/окончания периода появления событий, максимальное количество событий для загрузки и опции сортировки. Параметры startDate, endDate и maxResults могут быть цстановлны на null для отключения временного диапазона и ограничения количества.

Он возвращает список объектов Event, представляющих хронологические события.

Пример использования:

EntityList events = new EntityList("users.admin.devices.my_device", "my_device_event");

 

Iterator<Event> eventItr = Server.getDaoFactory().getEventDao().getEvents(cm, caller, entities, null, null, null, null, EventDao.EVENT_FIELD_CREATIONTIME, true);

 

while (eventItr.hasNext())

{

  Event ev = eventItr.next();

  Date eventTime = ev.getCreationtime();  

 

  DataTable eventData = ev.getData();

 

  // Processing

}

Использование вспомогательных констант

Интерфейс, который находится в пакете com.tibbo.aggregate.common.server, предоставляет константы строк, которые соединяются с большинством событий контекстов сервера и их полями.

Использование этих констант предпочтительнее, чем использование констант строк, определенных в вашем собственном коде. Это обеспечит безоткатные коды, если некоторые события или поля будут переименованы или перемещены в SberMobile Server в будущих версиях.