Создание серверов на основе POA
Для знакомства с работой компиляторов IDL2JAVA и IDL2CPP из комплектов VisiBroker for Java 4.0 и VisiBroker for C++ 4.0. создается тестовое описание на языке IDL и помещается в файл Test.idl:
interface Test
{
string operation(in char x);
};
Сначала запускается IDL-компилятор для Java командой
idl2java Test.idl
и просматриваются те файлы, которые получились в результате ее выполнения.
Первый файл — заглушка (stub) для соединения клиента с объектом — хранится в файле _TestStub.java. Имя заглушек создается по схеме _<имя интерфейса>.java. Сам интерфейс объекта Test описан в файле Test.java.
Скелет объекта, от которого следует реализовать сервант, именуется по схеме <имя интерфейса>POA.java (для интерфейса Test это будет TestPOA.java). Если скелет создается с использованием tie-механизма, то вместо обычного единственного класса скелета будут получены целых два: tie и operation. Первый именуется по схеме <имя интерфейса>POATie.java, а второй — <имя интерфейса>Operation.java. Компиляция IDL-описания приводит к появлению файлов TestPOATie.java и TestOperations.java.
В случае с POA, как и с основным объектным адаптером BOA, для интерфейса Test будут созданы Helper- и Holder-классы в файлах TestHelper.java и TestHolder.java. Holder-класс служит «оберткой» создаваемого объекта для передачи его через ORB.
Что касается Helper-класса, то его назначение заключается в предоставлении программисту полезных методов-утилит, как, например, методов bind для связывания с объектом: ссылка на объект вызывается методом bind(). Это справедливо как для объектного адаптера BOA, так и для переносимого POA. Поэтому можно считать, что написание программы-клиента для объектов, зарегистрированных с помощью POA, ничем не отличается от аналогичных действий, которые рассматривались в предыдущей работе. Тем не менее одно отличие в этих методах для разных объектных адаптеров есть: появился вариант, позволяющий найти объект, зарегистрированный в конкретном адаптере POA, для чего методу bind() в качестве одного из параметров передается полное имя POA.
Теперь возможно обратиться к ситуации с Си++ и запустить следующую команду:
idl2cpp test.idl
В результате появятся файлы test_c.cc, test_c.hh, test_s.cc и test_s.hh. Файлы с суффиксом _s хранят описания классов серверной части приложения CORBA, а с суффиксом _c — клиентской. Расширения .cc и .hh легко меняются опциями -src_suffix и -hdr_suffix компилятора IDL2CPP.
Типичный случай использования POA рассмотрен на примере языка Java.
Обычно работа сервера на POA состоит из нескольких шагов:
· получение ссылки на корневой адаптер POA;
· определение политик для нового POA;
· создание нового POA, порождаемого корневым POA;
· создание серванта и его активация;
· активация POA вызовом его менеджера.
Ззапустившись, типичный сервер CORBA считывает системные свойства и передает их методу инициализации брокера объектных запросов:
import org.omg.PortableServer.*;
public class POA_Server
{
public static void main(String[] args)
{
new POA_Server();
try
{
org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(args,System.getProperties());
}
}
Затем сервер получает ссылку на корневой объектный адаптер «RootPOA». Это производится посредством вызова специального метода resolve_initial_references(), часто используемого для инициализации различных служб CORBA. Поскольку возвращаемая ссылка имеет тип Object, ее нужно привести к типу POA с помощью метода narrow(), который находится в Helper-классе объекта POA:
POA poaRoot = POAHelper.narrow(orb.resolve_initial_references(«RootPOA»));
Теперь следует создать массив ссылок на объекты политик для нового POA и создать нужные экземпляры объектов. К примеру, необходимо создать дочерний POA, который будет хранить долгоживущие объекты, поэтому вызывается метод create_lifespan_policy(). Надо обратить внимание на тот факт, что этот метод вызывается для корневого объектного адаптера:
String new_POA_name = ”TestInterface_POA”;
org.omg.CORBA.Policy[] TestInterfacePolicies = {
poaRoot.create_lifespan_policy(LifespanPolicyValue.PERSISTENT)
};
Собственно создание POA заключается в вызове метода create_POA() корневого адаптера «RootPOA», которому передается имя создаваемого адаптера, ссылка на менеджер POA и массив объектов политик:
POA interface = poaRoot.create_POA(new_POA_name,poaRoot.the_POAManager(),TestInterfacePolicies);
Остается создать экземпляр серванта TestInterfaceImpl и передать ссылку на него методу активации серванта вместе с идентификатором объекта:
interface.activate_object_with_id(new_POA_name.getBytes(), new TestInterfaceImpl());
Когда готов POA с активным сервантом, следует активировать сам POA, вызвав метод activate() менеджера объектных адаптеров POA:
poaRoot.the_POAManager().activate();
Дело в том, что новый POA игнорирует запросы, адресуемые объекту, т.е. как бы выключен. Активизацией объектного адаптера «открывается кран» для запросов, и они начинают «течь» через POA к соответствующим сервантам.
Заключительный штрих в инициализации сервера — переход в цикл ожидания запросов, что делается вызовом run() брокера объектных запросов:
orb.run();
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
}
Это самый простой вариант сервера. Если создавать POA с сервантами по умолчанию или с менеджером сервантов, исходный текст будет отличаться. Вариантов построения серверов на POA — множество, все зависит от предполагаемой архитектуры создаваемых серверов. Большее о РОА можно узнать в «The Portable Object Adapter» версии 2.3 спецификации CORBA.