(модератор 31.01.2012): загружено в коллекцию как omcBusВ результате нехитрых комбинаций соображений по поводу обобщенной транспортной шины передачи сообщений между объектами родилась идея передавать сообщения не только между объектами, но и между модулями. Модули в данном случае отличаются от объектов тем, что у модулей всегда есть своё уникальное имя. Естественно было бы посылать сообщения модулю зная только лишь его символьное имя.
Интерфейс шины межмодульной передачи сообщений можно определить, например, так:
Код:
DEFINITION Bus;
TYPE
Message = ABSTRACT RECORD END;
HandleBusMessage = PROCEDURE (VAR msg: Message);
PROCEDURE Send (IN destination: ARRAY OF CHAR; VAR msg: Message; OUT ok: BOOLEAN);
END Bus.
Каждый модуль заинтересованный в возможности принятия и обработки таких сообщений должен экспортировать процедуру типа HandleBusMessage с именем "HandleBusMessage". В таком случае любой кто захочет, сможет передать этому модулю сообщение Message зная только лишь символьное имя модуля получателя.
PROCEDURE Send (IN destination: ARRAY OF CHAR; VAR msg: Message; OUT ok: BOOLEAN);
Отправка сообщения модулю.
Предусловие:
destination - имя модуля получателя;
msg - сообщение для этого модуля;
Постусловие:
ok = TRUE если модуль destination был найден и была найдена и вызвана экспортированная им процедура HandleBusMessage. В противном случае ok = FALSE (либо такой модуль не найден, либо он не экспортирует нужной процедуры).Пример использования транспортной шины межмодульной передачи сообщений:
Код:
MODULE TestBus;
IMPORT Log, Bus;
TYPE
HelloMsg = RECORD (Bus.Message) END;
PROCEDURE HandleBusMessage* (VAR msg: Bus.Message);
BEGIN
WITH msg: HelloMsg DO
Log.String("HelloMsg received!!!"); Log.Ln
ELSE
END
END HandleBusMessage;
PROCEDURE Test*; (* (!)TestBus.Test *)
VAR msg: HelloMsg; ok: BOOLEAN;
BEGIN
Bus.Send("TestBus", msg, ok) (* Отправка сообщения msg модулю "TestBus", т.е. самому себе *)
END Test;
END TestBus.
А вот и полная реализация модуля Bus средствами Meta-программирования:
Код:
MODULE Bus;
IMPORT Meta;
TYPE
Message* = ABSTRACT RECORD END;
HandleBusMessage* = PROCEDURE (VAR msg: Message);
PROCEDURE Send* (IN destination: ARRAY OF CHAR; VAR msg: Message; OUT ok: BOOLEAN);
VAR m, p: Meta.Item;
r: RECORD (Meta.Value) h: HandleBusMessage END;
BEGIN ok := FALSE;
Meta.Lookup(destination$, m);
IF m.obj = Meta.modObj THEN
m.Lookup("HandleBusMessage", p);
IF p.obj = Meta.procObj THEN
p.GetVal(r, ok);
IF ok THEN r.h(msg) END
END
END
END Send;
END Bus.
Для чего это можно использовать, наверное, и так понятно. Например, пусть есть модули А и В. Модуль В импортирует модуль А и вызывает его процедуры. Пусть теперь появился модуль А2 с таким же интерфейсом как и А, и нам вдруг захотелось, чтобы модуль В теперь работал с модулем А2. Поможет только перекомпиляция модуля В. Но ежели модуль В будет общаться с модулем А только зная его символьное имя, то надо будет просто заменить это имя на "А2", динамически, не останавливая работу. Кстати, после такого переключения, модуль А даже можно будет выгрузить из системы.
P. S. Следующим логическим шагом конечно же будет реализация remoting-шины, позволяющей посылать сообщения модулям запущенным на других компьютерах, т.е. по адресу: "адресIP:порт:модуль"

.