Обмен сообщениями между модулями
Glossary Item Box
Общие сведения
Модуль в Creatio является изолированной программной единицей. Ему ничего не известно об остальных модулях системы, кроме списка имен модулей, от которых он сам зависит. Подробнее модули Creatio описываются в статье "Принципы модульной разработки в Creatio".
Для организации взаимодействия разрозненных модулей между собой предназначен специальный объект — sandbox. Одним из ключевых механизмов, предоставляемых sandbox, является механизм обмена сообщениями между модулями.
Модули могут общаться друг с другом только посредством сообщений. Модуль, которому требуется сообщить об изменении своего состояния другим модулям в системе, публикует сообщение. Если модулю необходимо получать сообщения об изменении состояний других модулей, он должен быть подписанным на эти сообщения.
Чтобы модуль мог взаимодействовать с другими модулями системы, он должен импортировать в качестве зависимости модуль sandbox.
Указывать базовые модули в зависимостях ["ext-base", "terrasoft", "sandbox"] не обязательно, если модуль экспортирует конструктор класса. Объекты Ext, Terrasoft и sandbox после создания объекта класса модуля будут доступны как свойства объекта: this.Ext, this.Terrasoft, this.sandbox.
Регистрация сообщений
Чтобы модули могли обмениваться сообщениями, сообщения необходимо зарегистрировать.
Регистрация сообщений выполняется автоматически, если они объявлены в свойстве messages модуля.
Для регистрации сообщений модуля предназначен метод sandbox.registerMessages(messageConfig), где messageConfig — конфигурационный объект сообщений модуля.
Конфигурационный объект является коллекцией "ключ-значение", в которой каждый элемент имеет следующий вид:
"MessageName": {
mode: [Режим работы сообщения],
direction: [Направление сообщения]
}
Здесь "MessageName" — ключ элемента коллекции, содержащий имя сообщения. Значением является конфигурационный объект, содержащий два свойства:
- mode — режим работы сообщения. Должно содержать значение перечисления Terrasoft.MessageMode (Terrasoft.core.enums.MessageMode).
- direction — направление сообщения. Должно содержать значение перечисления Terrasoft.MessageDirectionType (Terrasoft.core.enums.MessageDirectionType).
Режимы обмена сообщениями (свойство mode):
- Широковещательный — режим работы сообщения, при котором количество подписчиков заранее неизвестно. Соответствует значению перечисления Terrasoft.MessageMode.BROADCAST.
- Адресный — режим работы сообщения, при котором сообщение может быть обработано только одним подписчиком. Соответствует значению перечисления Terrasoft.MessageMode.PTP.
В адресном режиме подписчиков может быть несколько, но сообщение обработает только один, как правило, последний зарегистрированный подписчик.
Направления сообщения (свойство direction):
- Публикация — модуль может только опубликовать сообщение в sandbox. Соответствует значению перечисления Terrasoft.MessageDirectionType.PUBLISH.
- Подписка — модуль может только подписаться на сообщение, опубликованное из другого модуля. Соответствует значению перечисления Terrasoft.MessageDirectionType.SUBSCRIBE.
- Двунаправленное — позволяет публиковать и подписываться на одно и то же сообщение в разных экземплярах одного и того же класса или в рамках одной и той же иерархии наследования схем (см. "Двунаправленные сообщения"). Соответствует значению перечисления Terrasoft.MessageDirectionType.BIDIRECTIONAL.
Пример регистрации сообщений модуля:
// Коллекция конфигурационных объектов сообщений. var messages = { "MessageToSubscribe": { mode: Terrasoft.MessageMode.PTP, direction: Terrasoft.MessageDirectionType.SUBSCRIBE }, "MessageToPublish": { mode: Terrasoft.MessageMode.BROADCAST, direction: Terrasoft.MessageDirectionType.PUBLISH } }; // Регистрация сообщения. this.sandbox.registerMessages(messages);
В схемах модели представления регистрировать сообщения с помощью метода sandbox.registerMessages() не нужно. Достаточно объявить конфигурационный объект сообщений в свойстве messages (см. "Сообщения. Свойство messages").
Для отказа от регистрации сообщений в модуле можно воспользоваться методом sandbox.unRegisterMessages(messages), где messages — имя или массив имен сообщений. Пример отмены регистрации сообщения:
// Отмена регистрации единичного сообщения. this.sandbox.unRegisterMessages("MessageToSubscribe"); // Отмена регистрации массива сообщений. this.sandbox.unRegisterMessages(["MessageToSubscribe", "MessageToPublish"]);
Добавление сообщений в схему модуля
Зарегистрировать сообщения можно также, добавив их в схему модуля с помощью дизайнера (см. "Дизайнер модуля").
Для добавления сообщения в схему модуля:
1. На вкладке [Структура] ([Structure]) дизайнера схемы модуля выделите узел [Messages] и, кликнув по нему правой кнопкой, выполните команду [Добавить] ([Add]) (рис. 1)
Рис. 1. — Добавление сообщения в структуру схемы модуля
2. Для добавленного сообщения установите необходимые свойства (рис. 2):
- [Название] ([Name]) — имя сообщения, совпадающее с ключом в конфигурационном объекте модуля.
- [Направление] ([Direction]) — направление сообщения. Возможные значения "Подписка" ("Follow") и "Публикация" ("Publish").
- [Режим] ([Mode]) — режим работы сообщения. Возможные значения "Широковещательное" ("Broadcast") и "Адрес" ("Address").
Рис. 2. — Свойства сообщения
В схемах модели представления добавлять сообщения в структуру схемы не нужно.
Публикация сообщения
Для публикации сообщения предназначен метод sandbox.publish(messageName , messageArgs, tags).
Параметры метода:
- messageName — строка, содержащая имя сообщения, например, "MessageToSubscribe".
- messageArgs — объект, передаваемый в качестве аргумента в метод-обработчик сообщения в модуле-подписчике. Если в методе-обработчике нет входящих параметров, то параметру messageArgs необходимо присвоить значение null.
- tags — массив тегов, позволяющий однозначно определить модуль, отправляющий сообщение. Как правило, используется значение [this.sandbox.id]. По массиву тегов sandbox определяет подписчиков и публикаторов сообщения.
Для сообщения, опубликованного с массивом тегов, будут вызваны только те обработчики, для которых совпадает хотя бы один тег. Сообщения, опубликованные без тегов, смогут обработать только подписчики без тегов.
Примеры вызова метода публикации сообщения:
// Публикация сообщения без аргумента и тегов. this.sandbox.publish("MessageWithoutArgsAndTags"); // Публикация сообщения без аргументов для метода-обработчика. this.sandbox.publish("MessageWithoutArgs", null, [this.sandbox.id]); // Публикация сообщения с аргументом для метода-обработчика. this.sandbox.publish("MessageWithArgs", {arg1: 5, arg2: "arg2"}, ["moduleName"]); // Публикация сообщения с произвольным массивом тегов. this.sandbox.publish("MessageWithCustomIds", null, ["moduleName","otherTag"]);
При публикации сообщения в адресном режиме можно получить результат его обработки подписчиком. Для этого метод-обработчик сообщения в модуле-подписчике должен вернуть соответствующий результат (см. "Подписка на сообщение"). Пример публикации такого сообщения:
// Объявление и регистрация сообщения. var messages = { "MessageWithResult": { mode: Terrasoft.MessageMode.PTP, direction: Terrasoft.MessageDirectionType.PUBLISH } }; this.sandbox.registerMessages(messages); // Публикация сообщения и получение результата его обработки подписчиком. var result = this.sandbox.publish("MessageWithResult", {arg1:5, arg2:"arg2"}, ["resultTag"]); // Вывод результата в консоль браузера. console.log(result);
При публикации сообщения в широковещательном режиме результат его обработки можно получить через объект, передаваемый в качестве аргумента для метода-обработчика:
// Объявление и регистрация сообщения. var messages = { "MessageWithResult": { mode: Terrasoft.MessageMode.BROADCAST, direction: Terrasoft.MessageDirectionType.PUBLISH } }; this.sandbox.registerMessages(messages); var arg = {}; // Публикация сообщения и получение результата его обработки подписчиком. // В методе-обработчике подписчика в объект нужно добавить свойство result, // в которое следует записать результат обработки. this.sandbox.publish("MessageWithResult", arg, ["resultTag"]); // Вывод результата в консоль браузера. console.log(arg.result);
Подписка на сообщение
Подписаться на сообщение можно, используя метод sandbox.subscribe(messageName, messageHandler, scope, tags).
Параметры метода:
- messageName — строка, содержащая имя сообщения, например, "MessageToSubscribe".
- messageHandler — метод-обработчик, вызываемый при получении сообщения. Это может быть анонимная функция или метод модуля. В определении метода может быть указан параметр, значение которого должно быть передано при публикации сообщения с помощью метода sandbox.publish().
- scope — контекст выполнения метода-обработчика messageHandler.
- tags — массив тегов, позволяющий однозначно определить модуль, который отправляет сообщение. По массиву тегов sandbox определяет подписчиков и публикаторов сообщения.
Примеры вызова метода подписки на сообщение:
// Подписка на сообщение без аргументов для метода-обработчика. // Метод-обработчик — анонимная функция. Контекст выполнения — текущий модуль. // Метод getsandboxid() должен вернуть тег, совпадающий с тегом опубликованного сообщения. this.sandbox.subscribe("MessageWithoutArgs", function(){console.log("Message without arguments")}, this, [this.getSandBoxId()]); // Подписка на сообщение с аргументом для метода-обработчика. this.sandbox.subscribe("MessageWithArgs", function(args){console.log(args)}, this, ["moduleName"]); // Подписка на сообщение с произвольным тегом. // Тег может быть любым из массива тегов опубликованного сообщения. // Метод-обработчик myMsgHandler должен быть реализован отдельно. this.sandbox.subscribe("MessageWithCustomIds", this.myMsgHandler, this, ["otherTag"]);
Для сообщения в адресном режиме метод-обработчик сообщения должен вернуть соответствующий результат. Пример подписки на такое сообщение:
// Объявление и регистрация сообщения. var messages = { "MessageWithResult": { mode: Terrasoft.MessageMode.PTP, direction: Terrasoft.MessageDirectionType.SUBSCRIBE } }; this.sandbox.registerMessages(messages); // Подписка на сообщение. this.sandbox.subscribe("MessageWithResult", this.onMessageSubscribe, this, ["resultTag"]); ... // Метод-обработчик реализован в модуле-подписчике. // args — объект, передаваемый при публикации сообщения. onMessageSubscribe: function(args) { // Изменение параметра. args.arg1 = 15; args.arg2 = "new arg2"; // Обязательный возврат результата. return args; },
Асинхронный обмен сообщениями
Если метод-обработчик сообщения в модуле-подписчике генерирует результат асинхронно, то необходимо использовать подход с функцией обратного вызова (callback-функцией).
Пример публикации сообщения и получения результата:
this.sandbox.publish("AsyncMessageResult", //Объект, передаваемый как аргумент функции-обработчика в подписчике. { // Функция обратного вызова. callback: function(result) { this.Terrasoft.showInformation(result); }, // Контекст выполнения функции обратного вызова. scope: this });
Пример подписки на сообщение:
this.sandbox.subscribe("AsyncMessageResult", // Функция-обработчик сообщения function(config) { // Обработка входящего параметра. var config = config || {}; var callback = config.callback; var scope = config.scope || this; // Подготовка результирующего сообщения. var result = "Message from callback function"; // Выполнение функции обратного вызова. if (callback) { callback.call(scope, result); } }, // Контекст выполнения функции-обработчика сообщения. this);
Пример модуля, использующего сообщения
Пример модуля, в котором реализована публикация и подписка на сообщение, приведен ниже:
define("UsrSomeModule", [], function() { Ext.define("Terrasoft.configuration.UsrSomeModule", { alternateClassName: "Terrasoft.UsrSomeModule", extend: "Terrasoft.BaseModule", Ext: null, sandbox: null, Terrasoft: null, messages: { "MessageToSubscribe": { mode: Terrasoft.MessageMode.PTP, direction: Terrasoft.MessageDirectionType.SUBSCRIBE }, "MessageToPublish": { mode: Terrasoft.MessageMode.BROADCAST, direction: Terrasoft.MessageDirectionType.PUBLISH } }, init: function() { this.callParent(arguments); this.sandbox.registerMessages(this.messages); this.processMessages(); }, processMessages: function() { this.sandbox.subscribe("MessageToSubscribe", this.onMessageSubscribe, this); this.sandbox.publish("MessageToPublish", null, [this.sandbox.id]); }, onMessageSubscribe: function() { console.log("'MessageToSubscribe' received"); }, destroy: function() { if (this.messages) { var messages = this.Terrasoft.keys(this.messages); this.sandbox.unRegisterMessages(messages); } this.callParent(arguments); } }); return Terrasoft.UsrSomeModule; });
Смотрите также
- Принципы модульной разработки в Creatio
- Типы модулей и их особенности
- Структура клиентской схемы
- Сообщения. Свойство messages
- Двунаправленные сообщения