Введение
Основные понятия
Простейшее приложение
Уровень прикладного программирования
Архитектура удаленного взаимодействия
Транспортный уровень передачи данных
Заключение

CORBA и RMI - две популярные объектные технологии для распределенных вычислений. В данной статье дается архитектурное сравнение этих технологий, с рассмотрением трех уровней абстракции: программной архитектуры приложений, архитектуры удаленного взаимодействия и архитектуры передачи данных на транспортном уровне. Предназначается статья главным образом для специалистов, знакомых с одной из рассматриваемых технологий для быстрого понимания архитектуры другой.

Введение

CORBA - технология построения распределенных объектных приложений, предложенная консорциумом OMG. Главный компонент стандарта CORBA - брокер объектных запросов (ORB), который действует как объектная шина, через которую обеспечивается прозрачное взаимодействие удаленных объектов. CORBA-объект виден внешнему миру через интерфейс, содержащий некоторое множество операций. Конкретный экземпляр CORBA-объекта идентифицируется объектной ссылкой. Удаленное приложение, являющееся клиентом CORBA-объекта, использует эту объектную ссылку для вызова нужной операции, при этом для разработчика создается впечатление, что объект находится в том же адресном пространстве. Брокер объектных запросов отвечает за поиск нужного удаленного объекта, подготавливает его для получения запроса, и обеспечивает передачу запроса к объекту. Реализация объекта взаимодействует с брокером объектных запросов через объектный адаптер или программный интерфейс ORB.

RMI - технология построения распределенных приложений, предложенная в спецификации языка Java. Объект, доступный для удаленных приложений, виден через опубликованный Java-интерфейс, содержащий некоторое множество методов. Один Java-объект может иметь несколько интерфейсов, каждый из которых характеризует определенное поведение этого объекта. Клиент взаимодействует с объектом через ссылку на один из интерфейсов, реализованных объектом. Обращение к удаленному объекту происходит аналогично обычному локальному вызову метода, т.е. прозрачно для разработчика. RMI поддерживает также передачу объектов из одного адресного пространства в другое, для чего используется технология сериализации объекта. Технология сериализации разработана специально для языка Java и обеспечивает распределение объектов по сети в реальном смысле этого слова.

Основные понятия:

Сервер объектов есть процесс, отвечающий за создание и управление экземплярами объектов;

Объект: RMI - сущность, идентифицируемая идентификатором класса;

CORBA - сущность, идентифицируемая именем интерфейса.

Метод или операция - функция, принадлежащая объекту. В терминах RMI принято употребление понятия метод. В терминах CORBA употребляется понятие операции. В дальнейшем эти два термина будут считаться взаимозаменяемыми.

Клиент есть процесс, вызывающий метод объекта.

Рассмотренные архитектуры поддерживают взаимодействие типа клиент-сервер. Для выполнения некоторого сервиса клиент вызывает метод, реализованный в удаленном объекте. Объект в этом случае выступает как сервер, модели клиент-сервер. Сервис, предоставляемый сервером, есть реализация объекта. Интерфейс, доступный для удаленного взаимодействия, описывается на языке IDL в случае CORBA, и на языке Java в случае использования RMI. Клиент взаимодействует с сервером посредством вызова методов, описанных в интерфейсе. Реализация же объекта скрыта от клиента. Используемые языки описания интерфейсов являются объектно-ориентированными и поддерживают инкапсуляцию, полиморфизм и наследование. CORBA IDL и интерфейсы на Java поддерживают множественное наследование. На уровне реализаций объектов в RMI множественное наследование классов не поддерживается, однако, объект может имплементировать несколько интерфейсов. В CORBA поддерживается множественное наследование и на этапе реализаций.

В обеих технологиях взаимодействие между клиентом и сервером объектов реализовано как вызов объектной удаленной процедуры (ORPC). Механизм работы RPC следующий (рис .1). Для вызова удаленной функции клиент обращается к клиентскому суррогату (client stub). Суррогат преобразует и упаковывает параметры, формируя сообщение запроса, которое затем передает транспортному протоколу для отправки серверу. Транспортный протокол передает сообщение серверному суррогату (server stub), который распаковывает содержимое запроса и вызывает реальный метод объекта. Во всех трех технологиях приняты разные названия для клиентского и серверного суррогатов, которые по сути означают одно и то же (proxy, stub, skeleton etc.).

Рисунок 1.
Схема взаимодействия приложений в RPC архитектуре.

В следующих разделах описывается простейший пример программы, реализованной в технологиях CORBA и RMI. Параллельно с разбором программы приводится пошаговое описание техники удаленного взаимодействия для каждой среды. Рассматриваются три уровня, по которым происходит сравнение технологий:

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

Простейшее приложение

Все фрагменты исходных кодов программ базируются на примере, названном Grid - таблица. Объект таблица (Grid) поддерживает двумерную таблицу, элементами которой являются целые числа. Объект класса Grid имеет две группы методов, манипулирующих значениями этой таблицы. Первая группа состоит из двух методов: get() и set(). Вторая группа имеет всего один метод - reset(). Клиент удаленного объекта вызывает метод set() для установки значения в нужной ячейке, затем проверяет записанное значение вызовом get(), после чего вызывает reset() для записи одинаковых значений во всю таблицу.

Интерфейсы объектов для CORBA и RMI спроектированы разными способами. В случае CORBA показывается множественное наследование на уровне языка IDL. Java же, напротив, не поддерживает множественное наследование на уровне реализаций, а на уровне описаний интерфейсов обеспечивает эту возможность. В случае Java спроектировано три интерфейса, один из которых является потомком двух других. Именно этот интерфейс реализуется затем в Java-классе.

При использовании CORBA-технологии были разработаны три IDL-интерфейса:

  • интерфейс grid1 содержит методы get() и set();
  • интерфейс grid2 - метод reset();
  • интерфейс grid наследует оба эти интерфейса, не определяя дополнительных методов.

В реализации объекта grid также использовано наследование реализации объекта grid1.По технологии RMI разработаны три интерфейса:

  • интерфейс grid1 содержит методы get() и set();
  • интерфейс grid2 - метод reset();
  • интерфейс grid наследует оба эти интерфейса, не определяя дополнительных методов.

Спроектированный объект реализует интерфейс grid. Тела методов также реализованы в объекте grid, поскольку в Java не поддерживается множественное наследование. Доступ к Java методам, однако, обеспечивается через интерфейсы, что позволяет инкапсуляцию в них специфичного поведения.

По каждой из трех технологий приводятся исходные коды, по которым наиболее наглядным образом можно сравнить технику программирования распределенных приложений. Первый файл, показанный в листинге 1, определяет интерфейсы объектов, и, соответственно, методы доступные для удаленного вызова. Суррогаты объектов на клиентской и серверной стороне генерируются IDL-транслятором в случае CORBA, а в технологии RMI - специальным компилятором rmic, поставляющемся в стандартном пакете jdk. По технологии RMI для того, чтобы интерфейс объекта определял методы, доступные для вызова удаленными клиентами, необходимо наследовать этот интерфейс от стандартного интерфейса java.RMI.Remote, необходимо также явно указать, что исключительная ситуация, обрабатываемая методами, есть java.rmi.RemoteException. Интерфейс Remote, определенный в пакете java.rmi не специфицирует ни одного дополнительного метода.

В листинге 2 показаны заголовочные файлы реализаций объектов для CORBA. Исходный код демонстрирует соотношение объектов с их интерфейсами. По технологии CORBA, IDL компилятор генерирует из определения интерфейса класс grid в заголовочном файле grid.hh. Этот файл затем используется при разработке и клиентского, и серверного приложений. Методы сгенерированного класса grid реализуются в отдельном классе grid_i, который пишется программистом. Существуют два способа соотнести класс реализации grid_i и интерфейсный класс grid: наследование и делегирование. В рассматриваемом примере применяется техника наследования для ассоциации этих классов. В файле grid.hh, кроме описания класса grid, генерируется также абстрактный класс gridBOAImpl. В его функции входит создание экземпляра объекта-суррогата в серверном приложении. Класс gridBOAImpl наследует класс grid, который в свою очередь наследует класс CORBA::Object. Все эти зависимости создаются автоматически IDL-компилятором, и разработчику нет необходимости писать подобный код самостоятельно. Класс grid_i наследует класс gridBOAImpl, что завершает отображение интерфейсного класса grid в класс реализации grid_i. Тип gridBOAImpl не специфицирован в CORBA и является частным решением продукта Orbix. Практически это делает непереносимым код серверного приложения между разными реализациями CORBA. Сейчас OMG устранил этот недостаток, разработав портируемый объектный адаптер (Portable Object Adapter). С использованием портируемого адаптера класс grid_i будет наследовать новый класс, называемый POA_grid. POA_grid будет стандартным типом в CORBA, что гарантирует переносимость исходного кода.

В листинге 3 показаны реализации методов серверных классов объектов. В листинге 4 отображены основные программы серверов приложений.

Серверная программа CORBA создает экземпляр класса grid_i и входит в цикл ожидания запросов клиентов в методе impl_is_ready(). Если сервер в течение определенного периода времени не получает запросов клиентов, он прекращает свою работу. Длительность периода ожидания устанавливается программистом. В зависимости от конфигурации и порядка активации объектов, запросы обрабатываются или в разных потоках, или последовательно в одном.

Весь серверный код для RMI-объектов показан в листинге 5. В данной технологии исходный код наиболее компактен и прост. Реализация сосредоточена в одном объекте gridImpl, поскольку в Java нет понятия заголовочных файлов. Для того чтобы соотнести класс реализации и Java-интерфейс, явно показывается, что класс gridImpl реализует интерфейс grid. Кроме того, чтобы наделить объект gridImpl поведением (т.е. методами), свойственным удаленным объектам, этот класс наследует Java-класс java.rmi.server.UnicastRemoteObject. Класс UnicastRemoteObject есть универсальный класс, обеспечивающий создание удаленных объектов. Этот класс, в свою очередь, наследует классы RemoteObject и RemoteServer, являющиеся основным каркасом для построения распределенных объектов. Класс gridImpl может реализовывать любое число интерфейсов, в нашем случае 2. Наследование класса UnicastRemoteObject - не обязательное требование. Класс gridImpl мог бы наследовать другой класс, обеспечивающий создание удаленного объекта. Естественно, класс gridImpl может определять и реализовывать дополнительные методы, не описанные в интерфейсах, но использовать эти методы можно будет только локально, а удаленным клиентам они будут не видны. Компилятор javac генерирует java байт-код для всех исходных текстов: интерфейсов grid, grid1, grid2 и класса реализации gridImpl. Затем специальным компилятором Java-интерфейсов rnic. Здесь можно провести аналогию с IDL - генерируются суррогаты клиентского и серверного объектов в виде двух файлов, соответственно, gridImpl_stub.class и gridImpl_skel.class. Многопотоковая обработка в Java RMI сделана более сложным образом. Вызовы клиентов, выполняющихся на разных виртуальных машинах, будут обрабатываться в различных потоках в серверном приложении. В том случае, когда вызовы делаются клиентом из одной виртуальной машины, обрабатываться они могут как в разных потоках, так и в одном. Сконфигурировать виртуальную машину таким образом, чтобы она гарантированно запускала собственный поток для нового вызова клиента, нельзя.

В листинге 6 показаны исходные коды клиентских приложений.

После компиляции программ в обеих технологиях требуется процесс регистрации серверного объекта. В CORBA регистрация выполняется с помощью записи в репозиторий реализаций ассоциации между именем интерфейса и полным именем исполняемого файла. В RMI регистрация производится программным способом. В теле метода main() вызывается метод rebind() класса Naming, где в качестве параметра указывается URL к исполняемому Java коду и ссылка на объект.

В данной статье не рассматриваются примеры, использующие динамический вызов объектов, при которых не требуется статической информации во время компиляции приложений. В CORBA компилятор IDL может сгенерировать информацию о типах для каждого метода и сохранить ее в специальной базе данных - репозитории интерфейсов. Клиент может запросить информацию о нужном ему интерфейсе и затем по полученным данным сформировать запрос к объекту через динамический интерфейс вызова (DII). Аналогично, на серверной стороне используется динамический интерфейс сервера (DSI), позволяющий клиенту вызывать операцию объекта, не знающего свой реальный тип на стадии компиляции.

Уровень прикладного программирования

Предыдущая глава иллюстрировала взгляд программиста на разработку прикладных приложений. Данная глава показывает более низкий уровень, который скрыт от программиста. Конкретно, описывается, каким образом клиент выполняет запрос к серверу, как сервер создает экземпляр объекта и экспортирует его в сеть. В целом разработка клиентской и серверной программ ведется, как будто они находятся в одном и том же адресном пространстве. Основные различия между CORBA и RMI в рассматриваемом контексте заключаются в том, как клиент указывает интерфейс, создает экземпляр объекта и вызывает метод удаленого объекта. Пошаговое описание показано в таблице 7.

Архитектура удаленного взаимодействия

Уровень удаленного взаимодействия обеспечивает инфраструктуру, создающую иллюзию того, что клиент и сервер находятся в одном адресном пространстве. В таблице 8 показаны действия, выполняемые для нахождения, запуска сервера, и программные сущности, задействованные при вызове метода удаленного объекта. Основные различие, на которых концентрируется внимание,- это способ регистрации серверов объектов и способы создания вспомогательных объектов-суррогатов.

Для того чтобы переслать данные между удаленными адресными пространствами, необходимо инициировать процессы маршализации (marshaling) и демаршализации (unmarshaling). Маршализация в целом означает упаковку запроса, включая параметры, возвращаемое значение, сам запрос, в стандартный формат, пригодный для передачи по сети. Демаршализация есть обратная операция, означающая распаковку всех данных в нужный формат представления данных (структуры, классы) в адресном пространстве процесса-получателя. Термин "маршализация" схож по значению с экстернализацией, однако в объектной терминологии экстернелизация употребляется в основном как внешнее представление экземпляра объекта.

Далее описываются несколько дополнительных терминов CORBA-технологии, используемых в таблице 8. Брокер запросов используется в распределенной системе как объектная шина. Объектный адаптер отвечает за подсоединение реализации объекта к брокеру запросов. Адаптер обеспечивает генерацию удаленных ссылок на объект, вызов метода, активацию и уничтожение объектов. Разные объекты системы требуют различные реализации объектных адаптеров: адаптер для базы данных, портируемый адаптер и т.д. В спецификации CORBA не определено, каким образом должна быть разработана функциональность брокера запросов и объектного адаптера. В Orbix эта функциональность реализована в процессе orbixd и двух библиотеках. Процесс orbixd нужен для поиска объекта в сети и его активации. В библиотеках обеспечиваются все остальные функции брокера запросов и объектного адаптера.

В RMI, как и в двух других технологиях, процессы маршализации запросов обеспечиваются суррогатами объектов в клиентском и серверном приложениях. Уровень вспомогательных объектов в RMI передает данные нижележащему уровню через так называемые управляющие потоки (marshaling streams). Управляющие потоки употребляют механизм сериализации объекта, с помощью которого Java-объект передается из одного адресного пространства в другое. Передача объектов производится их копированием в удаленное адресное пространство, кроме тех случаев, когда явно указывается, что требуется передача объектных ссылок. Серверный суррогат объекта, содержит метод, обрабатывающий запрос к реальному объекту. Суррогат отвечает за:

  • распаковку данных из управляющего потока;
  • вызов нужного метода реализации объекта;
  • упаковку возвращаемого значения или исключительной ситуации в управляющий поток.

В функции клиентского суррогата также входит упаковка данных в управляющий поток, информирование нижележащего уровня о начале вызова удаленного метода, распаковка из потока полученных данных и завершение вызова удаленного метода.

Транспортный уровень передачи данных

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

CORBA-спецификация не стандартизует сетевой протокол передачи данных между клиентом и сервером. Каждый производитель ORB фактически разрабатывает собственный протокол низкоуровневой передачи данных. Однако, для обеспечения интероперабельности брокеров запросов от разных производителей, OMG разработал общий протокол GIOP. Его отображение в TCP/IP специфицировано в CORBA и получило название протокола Internet Inter ORB Protocol (IIOP). С его помощью стандартизуется формат представления данных, объектных ссылок и обеспечивается взаимодействие брокеров разных производителей.

На транспортном уровне RMI использует два протокола: сериализации Java объектов и HTTP. Протокол сериализации используется для упаковки данных и возвращаемых значений. Протокол HTTP используется для отправки вызова удаленного метода и получения обратных данных. Формат передачи данных для RMI представляется потоком (stream). Сообщения подразделяются на два типа: исходящие (out) и входящие(in). Исходящие сообщения в свою очередь могут быть трех типов: Call, Ping, DgcAck. Call обозначает вызов удаленного метода. Ping используется для проверки работоспособности удаленной виртуальной машины, DgcAck есть подтверждение, посылаемое в серверный сборщик мусора. Это подтверждение обозначает, что удаленный объект в виде возвращаемого значения сервера, получен клиентом. Формат входящих сообщений также делится на три типа: ReturnData, HttpReturn, PingAck. ReturnData есть результат нормального вызова RMI. HttpReturn - результат вызова, сделанного по протоколу HTTP. PingAck - подтверждение на полученное сообщение Ping.

Транспортный уровень RMI состоит из 4 абстрактных понятий:

  • endpoint - конечное адресное пространство или виртуальная машина;
  • channel - абстракция канала между двумя виртуальными машинами;
  • connection - соединение, позволяющее ввод и вывод данных;
  • transport - транспортный программный компонент RMI, управляющий каналами. Компонент обеспечивает единственный канал между двумя виртуальными машинами Java. Транспорт отвечает за прием удаленных вызовов, установки соединения с объектом, обработку данных для вышележащих уровней.

Отправляемые и возвращаемые данные в RMI форматируются протоколом сериализации Java-объектов. Каждый вызов метода кодируется идентификатором, номером метода, который должен быть вызван, хэш-кодом для нахождения нужного суррогата объекта и списком параметров вызова. Возвращаемые данные в RMI состоят из кода, обозначающего нормальную или исключительную ситуацию, идентификатора и возвращаемого значения.

HTTP-протокол используется для вызова удаленных методов через брэндмауер (firewall). В этом случае заголовок сообщения содержит URL, указывающий сервер и порт для подсоединения к RMI-серверу (http://host:port). Все сообщения пересылаются стандартным HTTP-протоколом с использованием команды POST.

Заключение

Описанные сравнительные характеристики показывают достаточную схожесть архитектур CORBA и RMI. Главная черта технологий - обеспечение инфраструктуры для прозрачного взаимодействия удаленных объектов в сети. Основные отличия описываются ниже.

CORBA поддерживает наследование на уровне реализации объектов. Каждая реализация CORBA-интерфейса наследует объект CORBA::Object. Конструктор этого объекта всегда выполняет действия по регистрации объекта, генерации объектной ссылки, созданию экземпляра объекта суррогата и т.д. CORBA не привязана к транспортному протоколу. В настоящий момент вопрос портируемости исходного кода рассматривается консорциумом OMG введением спецификации портируемого объектного адаптера. С помощью протокола IIOP обеспечивается интероперабельность брокеров запросов от разных производителей.

RMI обеспечивает реализацию объектов, имеющих несколько интерфейсов. Реализация удаленного объекта должна наследовать класс, обеспечивающий поведение, видимое внешним приложениям. RMI-технология специализирована для языка Java. Портируемость байт-кода обеспечивается между любыми платформами, реализующими соответствующую Java-машину. В RMI обеспечивается передача удаленного объекта по ссылке и по значению. RMI обеспечивает динамическую загрузку классов в клиентское и серверное приложение. Текущий транспортный протокол реализован на основе TCP, но в следующих реализациях будет использован также UDP.

В заключение необходимо отметить, что часто возникающий принципиальный спор о превосходстве той или иной технологии некорректен. Как было показано, наряду с общей схожестью каждая технология имеет свои существенные отличия, которые и должны быть проанализированы применительно к конкретной задаче. Общая тенденция, которая касается применения технологий в том или ином проекте такова:

  • там, где требуется объединить разнородную программно-аппаратную среду, используя разные языки программирования и разные аппаратные платформы, целесообразно использовать CORBA технологию;
  • в чистой Java-среде, где вся система разрабатывается на этом языке, целесообразно использовать RMI-технологию.

Листинг 1.
Java-интерфейс
файл grid1.java
package examples.grid;
public interface grid1 extends java.rmi.Remote {
      long get (short n,short m) throws java.rmi.RemoteException;
      void set (short n,short m, long value) throws java.rmi.RemoteException;
}
файл grid2.java

package examples.grid;
public interface grid2 extends java.rmi.Remote {
       void reset (long value) throws java.rmi.RemoteException;
}

файл grid.java

package examples.grid;
public interface grid extends grid1,grid2 {
}

CORBA IDL
interface grid1
{
        long get (in short n, in short m);
        void set (in short n, in short m, in            
                           long value);
};

interface grid2
{
            void reset (in long value);
};

interface grid : grid1, grid2
{
};
Листинг 2.
Заголовочный файл CORBA

#include "grid.hh"

class grid1_i: public gridBOAImpl {
public: 
  grid1_i (CORBA::Short h,
               CORBA::Short w);

virtual ~grid1_i();
virtual void set(
           CORBA::Short n, 
           CORBA::Short m,
           CORBA::Long value,
           CORBA::Environment &env);
virtual CORBA::Long get(
             CORBA::Short n,
             CORBA::Short m,
             CORBA::Environment &env);
protected:
  CORBA::Long **m_a;
  CORBA::Short m_height, m_width;
};

class grid2_i : public gridBOAImpl {
public:
  grid2_i(){};
  ~grid2_i(){};
  virtual void reset(CORBA::Long value,
        CORBA::Environment &env) = 0;
};



class grid_i : public grid1_i,
                     public grid2_i,
                    public gridBOAImpl 
{
public:
  virtual void reset(CORBA::Long value,
                   CORBA::Environment &env);
  grid_i(CORBA::Short h,
          CORBA::Short w) : grid1_i(h,w){};
  ~grid_i(){};
};
Листинг 3.
Исходный код методов CORBA

void grid1_i :: set( CORBA::Short n, 
                             CORBA::Short m,
                             CORBA::Long value,
                           CORBA::Environment &env)
{
  m_a[n][m] = value;
}
CORBA::Long grid1_i :: get( ORBA::Short n,
                            CORBA::Short m,
                          CORBA::Environment &env)
{
  return m_a[n][m];
}

void reset(CORBA::Long value,
                   CORBA::Environment &env)
{short n,m;
for (n = 0; n

Листинг 4.
main программа CORBA

int main()
{
   // создание объекта grid, используя класс
   // реализации grid_i
  
  grid_i OurGrid(100,100);
  try {
    CORBA::Orbix.impl_is_ready("grid");
  }
  catch(...) 
  {
     count << "Unexpected exception" << endl;
     exit (1);
  }
Листинг 5.
Исходный код программы на Java

package examples.grid;

import java.rmi.*;
import java.rmi.server.UnicastRemoteObject;

public class gridImpl extends UnicastRemoteObject
implements grid
{
  private long m_a[][];
  private short m_height, m_width;

  public gridImpl(short h, short w) throws RemoteException {
    super();
    m_height = h;
    m_width = w;
    m_a = new long[h][w];
  }
  
  public void set(short n, short m, long value)  throws RemoteException
  {
    m_a[n][m] = value;
  }
}	  
  public long get(short n, short m)  throws RemoteException
  {
    return m_a[n][m];
  }
 public void reset(long value) throws RemoteException
  {
    short n,m;
    for (n = 0; n < m_width; n++)
      for (m = 0; m < m_height; m++)
	m_a[n][m] = value;
    return;
  }

  public static void main(String args[])
  {
    //инициализация объекта SecurityManager
    System.setSecurityManager(new RMISecurityManager());
    try {
      gridImpl obj = new gridImpl((short)10,(short)10);
      Naming.rebind("//sun-yuri/Grid", obj);

      System.out.println("Grid bound in registry");
    }
    catch(Exception e) {
      System.out.println("Grid err: " + e.getMessage());
      e.printStackTrace();
    }
  } 
}
Листинг 6.
Код приложения клиента RMI

package examples.grid;

import java.awt.*;
import java.rmi.*;

public class gridApplet extends java.applet.Applet {
  long value = 0;
  public void init() {
    try {
      grid obj = (grid)Naming.lookup("//" + getCodeBase().getHost() +
				       "/Grid");
     value = obj.get((short)0,(short)1);
      obj.reset(value+1);
    }
    catch(Exception e)
    {
      System.out.println("gridApplet exception: " + e.getMessage());
      e.printStackTrace();
    }
  }
  public void paint (Graphics g) {
    g.drawString (String.valueOf(value), 25, 50);
  }
}
код приложения клиента CORBA

#include "grid.hh"

void main(int argc, char** argv)
{
  grid_var gridVar;
  CORBA::Long value;
  
  //подсоединение к CORBA объекту
  gridVar = grid::_bind(":grid");

  value = gridVar->get(0,0);

  gridVar->reset(value+1);
}

Таблица 7.

CORBA RMI
1. Клиент вызывает метод grid::bind(). Этот метод есть статическая функция объекта-суррогата.
2. Брокер запросов запускает сервер, содержащий объект, который реализует интерфейс grid.
3. Как показано в функции main, сервер создает экземпляр объекта. Сервер вызывает метод CORBA::BOA::impl_is_ready(), что обозначает окончание инициализации, и сообщает брокеру запросов, что объект готов получать запросы клиентов.
4. Брокер запросов возвращает объектную ссылку на интерфейс grid как указатель на объект класса grid_var.
1. К моменту обращения клиента к серверу должен быть создан экземпляр объекта Grid и его суррогата.
2. Далее объект должен быть зарегистрирован в службе именований, как показано в функции main. Регистрация осуществляется вызовом метода rebind, который обращается к серверу registry. Registry есть простейший сервис именований объектов.
3. Клиент обращается к сервису именований объектов посредством вызова метода lookup.
4. В адресное пространство клиента динамически загружается суррогат объекта
5. Создается экземпляр объекта-суррогата на стороне клиента. Метод lookup возвращает ссылку на удаленный объект. В общем случае экземпляр объекта должен находиться в активном состоянии. В том случае, если объект сохранен в долговременной памяти, то при обращении к нему клиента, он будет активирован сервером registry.
1. Клиент вызывает метод объекта суррогата get(), который передает управление методу get(), реализованному в серверном объекте grid_i.
2. Аналогично вызов метода gridVar->reset() передает управление grid_i::reset().
1 Действия происходят аналогично CORBA. Вызывается метод get() объекта суррогата, передающий управление в метод get() серверного объекта.
2. Для вызова метода reset() необходимо получить ссылку на интерфейс grid2. Это можно сделать либо явным преобразованием типов, либо вторичным запросом к сервису имен. Экземпляр объекта суррогата на стороне клиента используется один и тот же, однако вызов методов get() и set() разрешен через переменную типа grid, а вызов метода reset()-через переменную типа grid2. Т.е. вызов определенного метода осуществляется через ссылку на тот интерфейс, в котором этот метод описан.

Таблица 8.

CORBA RMI
1. Вызов статического метода grid::bind() дает задание брокеру запросов найти нужный объект в системе.
2. Брокер находит объект в репозитории и получает оттуда путь к исполняемому файлу. В Orbix может быть также использован сервис локации, позволяющий узнать, на каком хосте сети расположен нужный объект. По полученному имени файла ORB запускает сервер.
3. Сервер при старте создает экземпляры всех объектов, включая объект grid из класса grid_i. Как показывалось, класса grid_i косвенно наследует класс CORBA::Object, чей конструктор вызывает метод BOA::create(), давая на вход уникальный идентификатор, и получая объектную ссылку. Затем объектная ссылка регистрируется в брокере запросов вызовом obj_is_ready().
4. Конструктор класса grid_i создает экземпляр объекта суррогата.
5. Брокер запросов возвращает объектную ссылку клиенту, где создается клиентский суррогат объекта и регистрируется в таблице объектов суррогатов с соответствующей объектной ссылкой. 6. Клиент получает объектную ссылку как указатель на объект суррогат - gridVar.
1.Клиент вызывает метод сервиса имен lookup() для получения ссылки на удаленный объект. Сервис имен обращается к процессу registry. По заданному имени объекта registry находит ссылку, если объект не активен, запускает соответствующий сервер.
2. При старте сервера создается экземпляр объекта RMISecurityManager, позволяющий загрузку нелокальных Java классов.
3. Создается объект класса gridImpl, реализующего интерфейсы grid, grid2. Поскольку этот объект наследует класс UnicastRemoteObject, вызывается конструктор класса родителя, который и создает и экспортирует в сеть удаленный объект. Он создает экземпляр объекта-суррогата.
4. Объект может быть перерегистрирован в сервисе имен (registry) - вызовом метода rebind().
5. Процесс registry возвращает в метод lookup ссылку на зарегистрированный объект.
6. В адресное пространство клиента передаются классы клиентского суррогата и создается экземпляр вспомогательного объекта.
7. Клиентский суррогат имеет то же множество методов, что и реальный объект. Вызов этих методов осуществляет маршализацию запроса. Клиент получает объектную ссылку obj на объект-суррогат в результате работы метода lookup().
7. При вызове метода gridVar->get() вызываеся соответствующий метод объекта-суррогата. Суррогат создает псевдо-объект Request, упаковывает параметры в этот объект и вызывает метод Request::invoke(). Этот метод передает запрос в коммуникационный канал посредством вызова метода CORBA::Request::send(). Далее объект вызывает метод CORBA::Request::get_response() и ждет ответа от сервера.
8. При получении сервером сообщения с запросом, управление передается базовому объектному адаптеру (БОА). БОА находит нужный суррогат серверного объекта и передает ему запрос.
9. Суррогат распаковывает параметры из полученного объекта Request, по имени метода находит нужный метод реального объекта и вызывает его. Затем суррогат получает возвращаемое значение, упаковывает его и завершает работу. БОА формирует сообщение и кладет его передаваемый буфер.
10. Буфер передается клиенту и считывается методом CORBA::Request::get_response(), ожидающим ответа. Сообщение считывается из буфера и обрабатывается суррогатом, распаковывающим возвращаемые значения, исключительные ситуации. Результат передается в метод gridVar->get().
11. Вызов метода gridVar->reset() производится по аналогичной схеме.
1.Вызов метода obj.get() есть вызов метода клиентского объекта-суррогата. Суррогат содержит ссылку на интерфейс RemoreRef, который отвечает за обработку запроса к удаленному объекту. Вызывается метод newCall, описанный в этом интерфейсе, с указанием номера вызываемой операции, и хэш кода, идентифицирующего удаленный объект. Метод newCall упаковывает параметры запроса в объект, реализующий интерфейс RemoteCall.
2. Вызывается метод invoke(), передающий RemoteCall на транспортный уровень. invoke() ожидает отработки удаленного метода и возвращаемых параметров. Из сообщения запроса формируется поток.
3. Поток передается серверу, где из сообщения формируется тот же объект RemoteCall. Он передается в суррогат объекта, где обрабатывается методом dispatch().
4. Суррогат находит по хэш-коду нужный реальный объект, по номеру - вызываемый метод, распаковывает параметры из RemoteCall и вызывает реальный метод get() объекта. dispatch() ожидает завершения работы метода.
5. Возвращаемые параметры упаковываются обратно в RemoteCall, который передается на транспортный уровень и затем клиенту.
6. Потоковое сообщение, полученное транспортным уровнем клиента, расшифровывается и возвращается в ожидающий ответа метод invoke(). Суррогат объекта, получив возвращаемые параметры в RemoteCall, распаковывает их и передает в метод get().
7. Создается ссылка на интерфейс grid2 явным преобразованием типов из ссылки на grid. Ссылка остается на тот же реальный объект-суррогат, но видимые методы теперь те, которые определены в интерфейсе grid2.
8. Вызов метода obj2.reset() производится по аналогичной технологии.

Таблица 9.

CORBA RMI
1. Вызов метода bind() обращается к брокеру запросов для получения объектной ссылки. Управление передается сначала брокеру, работающему на стороне клиента. Он запрашивает сервис локации (конфигурационный файл), по которому определяется местонахождение удаленного объекта. Соответствующий запрос отправляется серверному брокеру запросов по TCP/IP.
2. В момент старта сервера создается объект grid и, как показывалось, вызываются конструктор CORBA::Object, а затем метод BOA::create(). BOA создает сетевой сокет, объекту grid присваивается идентификатор, создается объектная ссылка. Если взаимодействие происходит по протоколу IIOP, то объектная ссылка имеет вид Interoperable Object Reference (IOR). Эта ссылка содержит имя хоста, TCP/IP-порт, код объекта в сервере. BOA регистрирует ссылку для брокера запросов.
3. Когда ссылка передается клиенту (в результате работы метода bind()), суррогат объекта получает адрес получателя и устанавливает сетевое соединение на основе сокетов.
1.Вызовом метода lookup() клиент обращается к службе имен, через которую получает зарегистрированную объектную ссылку.
2. Для соединения с серверным объектом создается объект типа RMISocketFactory и вызывается метод createSocket() для заданного порта и хоста.
3. Во время старта сервера вновь созданный объект регистрируется в сервисе имен registry. Создается объект типа UnicastRemoteObject - экспортирующий объект. При регистрации формируется его объектная ссылка. Объектная ссылка состоит из идентификатора виртуальной Java-машины (endpoint) и, в ее пределах, идентификатора конкретного объекта. Такая ссылка в терминах RMI называется "живая" (live reference). Экспортируется объект присваиванием ему анонимного порта.
4. На стороне сервера также создается объект RMISocketFactory и вызывается метод createServerSocket() на заданном порту. Серверный сокет автоматически определяет, если пришедшее к нему сообщение есть пакет протокола HTTP POST.
1. Вызов метода bind() обращается к брокеру запросов для получения объектной ссылки. Управление передается сначала брокеру, работающему на стороне клиента. Он запрашивает сервис локации (конфигурационный файл), по которому определяется местонахождение удаленного объекта. Соответствующий запрос отправляется серверному брокеру запросов по TCP/IP.
2. В момент старта сервера создается объект grid и, как показывалось, вызываются конструктор CORBA::Object, а затем метод BOA::create(). BOA создает сетевой сокет, объекту grid присваивается идентификатор, создается объектная ссылка. Если взаимодействие происходит по протоколу IIOP, то объектная ссылка имеет вид Interoperable Object Reference (IOR). Эта ссылка содержит имя хоста, TCP/IP-порт, код объекта в сервере. BOA регистрирует ссылку для брокера запросов.
3. Когда ссылка передается клиенту (в результате работы метода bind()), суррогат объекта получает адрес получателя и устанавливает сетевое соединение на основе сокетов.
1.При вызове метода obj.get() суррогат упаковывает параметры в формат сериализованного объекта (Object Serialization).
2. По установленному соединению, через сокеты, созданные объектом RMISocketFactory, сообщение передается серверу. Клиентское приложение обеспечивает три типа пересылки сообщения. Первая попытка делается отправить сообщение непосредственно в удаленный сокет. Если наложены некоторые ограничения - установлен firewall, сообщение передается по протоколу HTTP протоколу и автоматически распознается сервером. В том случае если объект недоступен по HTTP напрямую, клиент пытается подсоединиться к CGI скрипту, перенаправляющему клиента к новому сетевому порту.
3. Возвращаемые значения метода также кодируются форматом прокола сериализации объектов.

Юрий Пуха, Jet InfoSystems. Тел. 972-1182