![]() Проекты на Аде Уроки Ады Документация Конференции Разработки Примеры Каталог ПО Полезные ссылки Поиск в Сети Скачать Прочее |
Использование CORBA для объектного доступа к базе данныхВадим Годунко <vgodunko@gmail.com>, 2007 г. Начальная реализация сервераВ качестве примера будем разрабатывать интерфейс справочника пользователей. Каждый пользователь будет описываться одним объектом. Дополнительно потребуется объект-фабрика для создания новых пользователей и объект-поисковик для поиска в справочнике. Файл описания интерфейса users.idl будет выглядеть следующим образом:
module Users {
interface User {
attribute wstring name;
attribute wstring surname;
};
typedef sequence<User> UserSequence;
interface UserFactory {
User create(in wstring name, in wstring surname);
};
interface UserFinder {
UserSequence by_name (in wstring name);
};
};Далее, с помощью программы трансляции IDL в Ada - idlac - сгенерируем необходимые клиентские, серверные файлы и заготовки реализации объектов:
idlac -c users.idl
idlac -s users.idl
idlac -i users.idlТеперь всё готово для написания сервера. Объекты конечно не смогут выполнять свои функции, но сервер будет запускаться создавать необходимые объекты и ожидать запросов. В процессе совершенствования программы приведённый ниже код останется практически неизменным.
with Ada.Text_IO;
with CORBA.Object;
with CORBA.ORB;
with PortableServer.POA.Helper;
with PortableServer.POAManager;
with PolyORB.Setup.No_Tasking_Server;
-- Конфигурирование PolyORB для работы в режиме обычного многозадачного
-- сервера.
with Users.UserFactory.Impl;
with Users.UserFinder.Impl;
procedure Server is
begin
-- Инициализация ORB.
declare
Argv : CORBA.ORB.Arg_List := CORBA.ORB.Command_Line_Arguments;
begin
CORBA.ORB.Init (CORBA.ORB.To_CORBA_String ("ORB"), Argv);
end;
declare
Root_POA : PortableServer.POA.Local_Ref;
begin
-- Получение ссылки на корневой объектный адаптер.
Root_POA :=
PortableServer.POA.Helper.To_Local_Ref
(CORBA.ORB.Resolve_Initial_References
(CORBA.ORB.To_CORBA_String ("RootPOA")));
-- Активация корневого объектного адаптера.
PortableServer.POAManager.Activate
(PortableServer.POA.Get_The_POAManager (Root_POA));
-- Создание объекта-фабрики и объектной ссылки на этот объект.
declare
Ref : CORBA.Object.Ref;
begin
Ref :=
PortableServer.POA.Servant_To_Reference
(Root_POA,
new Users.UserFactory.Impl.Object);
-- Вывод на экран сформированной объектной ссылки.
Ada.Text_IO.Put_Line
("'"
& CORBA.To_Standard_String (CORBA.Object.Object_To_String (Ref))
& "'");
end;
-- Создание объекта-поисковика и объектной ссылки на этот объект.
declare
Ref : CORBA.Object.Ref;
begin
Ref :=
PortableServer.POA.Servant_To_Reference
(Root_POA,
new Users.UserFinder.Impl.Object);
-- Вывод на экран сформированной объектной ссылки.
Ada.Text_IO.Put_Line
("'"
& CORBA.To_Standard_String (CORBA.Object.Object_To_String (Ref))
& "'");
end;
end;
-- Передача нити главной подпрограммы в ведение ORB.
CORBA.ORB.Run;
end Server;Собрать программу сервера можно командой:
gnatmake server.adb `polyorb-config`Для исключения иногда возникающих проблем с отсутствием настройки протокола группового вещания и экспериментальными функциями PolyORB содадим файл polyorb.conf следующего содержания: ## Управление точками доступа. [access_points] srp=disable soap=disable iiop=enable iiop.ssliop=disable diop=disable uipmc=disable ## Управление поддерживаемыми протоколами. [modules] binding_data.srp=disable binding_data.soap=disable binding_data.iiop=enable binding_data.iiop.ssliop=disable binding_data.diop=disable binding_data.uipmc=disable Теперь можно запустить программу и получить что-то подобное: $ server 'IOR:01aaaaaa1a00000049444c3a55736572732f55736572466163746f72793a312e3000aaaa0 1000000000000005c000000010102aa0a0000003132372e302e302e3100e6841b0000002f30303 03030303031315463663966653565386331623431643032aa01000000010000001c00000001aaa aaa010001000000000000010100020000000101010002010100' 'IOR:01aaaaaa1900000049444c3a55736572732f5573657246696e6465723a312e3000aaaaaa0 1000000000000005c000000010102aa0a0000003132372e302e302e3100e6841b0000002f30303 03030303031325463663966653565386331623431643032aa01000000010000001c00000001aaa aaa010001000000000000010100020000000101010002010100' Две длинные строки непонятных символов есть текстовое представление объектных ссылок. В нашем случае первая является объектной ссылкой на объект-фабрику, а вторая - на объект-поисковик. po_catrefТекстовое предстваление объектных ссылок совершенно не предназначено для использования человеком, хотя и несёт в себе много полезной информации. Преобразовать объектную ссылку в понятный человеку вид может программа po_catref. В нашем примере мы получми следующую информацию:
$ po_catref 'IOR:01aaaaaa1a00000049444c3a55736572732f55736572466163746f72793a3
12e3000aaaa01000000000000005c000000010102aa0a0000003132372e302e302e3100e6841b0
000002f3030303030303031315463663966653565386331623431643032aa01000000010000001
c00000001aaaaaa010001000000000000010100020000000101010002010100'
Parsing stringified reference: IOR:01aaaaaa1a00000049444c3a55736572732f5573657
2466163746f72793a312e3000aaaa01000000000000005c000000010102aa0a0000003132372e3
02e302e3100e6841b0000002f3030303030303031315463663966653565386331623431643032a
a01000000010000001c00000001aaaaaa010001000000000000010100020000000101010002010
100
Type Id: IDL:Users/UserFactory:1.0
Found: 1 profiles in IOR
Profile number: 1
IIOP Version: 1.2
Host Name: localhost
Address: 127.0.0.1
Family: FAMILY_INET
Port: 34022
Object_Id: 2f3030303030303031315463663966653565386331623431643032
Tagged components: 1
Component #1:
Tag: 1
Type: TAG_Code_Sets
SNCS-C: 0x00010001; ISO 8859-1:1987; Latin Alphabet No. 1
SNCS-W: 0x00010100; ISO/IEC 10646-1:1993; UCS-2, Level 1
SCCS-W: 0x00010101; ISO/IEC 10646-1:1993; UCS-2, Level 2
SCCS-W: 0x00010102; ISO/IEC 10646-1:1993; UCS-2, Level 3
$ po_catref 'IOR:01aaaaaa1900000049444c3a55736572732f5573657246696e6465723a312
e3000aaaaaa01000000000000005c000000010102aa0a0000003132372e302e302e3100e6841b0
000002f3030303030303031325463663966653565386331623431643032aa01000000010000001
c00000001aaaaaa010001000000000000010100020000000101010002010100'
Parsing stringified reference: IOR:01aaaaaa1900000049444c3a55736572732f5573657
246696e6465723a312e3000aaaaaa01000000000000005c000000010102aa0a0000003132372e3
02e302e3100e6841b0000002f3030303030303031325463663966653565386331623431643032a
a01000000010000001c00000001aaaaaa010001000000000000010100020000000101010002010
100
Type Id: IDL:Users/UserFinder:1.0
Found: 1 profiles in IOR
Profile number: 1
IIOP Version: 1.2
Host Name: localhost
Address: 127.0.0.1
Family: FAMILY_INET
Port: 34022
Object_Id: 2f3030303030303031325463663966653565386331623431643032
Tagged components: 1
Component #1:
Tag: 1
Type: TAG_Code_Sets
SNCS-C: 0x00010001; ISO 8859-1:1987; Latin Alphabet No. 1
SNCS-W: 0x00010100; ISO/IEC 10646-1:1993; UCS-2, Level 1
SCCS-W: 0x00010101; ISO/IEC 10646-1:1993; UCS-2, Level 2
SCCS-W: 0x00010102; ISO/IEC 10646-1:1993; UCS-2, Level 3Как видно из примеров, объектная ссылка состоит из профайлов. В наших примерах всегда будет только один профайл, но это совершенно не обязательно. Каждый профайл в свою очередь определяет используемый для взаимодействия с объектом протокол (у нас всегда будет IIOP), адресную информацию точки доступа TCP/IP, внутренний ключ объекта и дополнительную информацию в виде тэговых компонентов. Наибольший интерес будет представлять адресная информация: точка доступа и ключ объекта. Точка доступа описывает характеристики используемого транспортного протокола, в нашем случае это TCP/IP. Ключ объекта представляет уникальный идентификатор объекта внутри программы сервера. Именно по ключу объектна ORB различает различные объекты внутри себя. Можно заметить, что информация точки доступа в обоих объектных ссылках одинакова, а объектные ключи - различаются. Если поэксперементировать с перезапуском сервера, то можно заметить, что каждый раз и точка доступа и объектные ключи будут меняться. Доработка сервераТеперь можно реализовать основные функции сервера. Для этого достаточно заполнить сгенерированные idlac-ом шаблоны реализации. Кроме этого дополнительно добавлен пакет Globals в котором хранится список объектных ссылок всех созданных пользователей. Далее приводится полный текст всех изменённых файлов с необходимыми комментариями.
with Ada.Containers.Vectors;
with Users.User;
package Globals is
package User_Vectors is
new Ada.Containers.Vectors (Positive, Users.User.Ref, Users.User."=");
Users : User_Vectors.Vector;
end Globals;
with CORBA;
with PortableServer;
package Users.User.Impl is
type Object is new PortableServer.Servant_Base with private;
type Object_Ptr is access all Object'Class;
function Get_name (Self : access Object) return CORBA.Wide_String;
procedure Set_name (Self : access Object; To : in CORBA.Wide_String);
function Get_surname (Self : access Object) return CORBA.Wide_String;
procedure Set_surname (Self : access Object; To : in CORBA.Wide_String);
function New_User (Name : in CORBA.Wide_String;
Surname : in CORBA.Wide_String)
return Object_Ptr;
private
type Object is new PortableServer.Servant_Base with record
Name : CORBA.Wide_String;
Surname : CORBA.Wide_String;
end record;
end Users.User.Impl;
with Users.User.Skel;
-- Осуществляем подключение файла скелетона - специального кода для
-- преобразования запростов в вызовы подпрограмм.
package body Users.User.Impl is
function Get_name (Self : access Object) return CORBA.Wide_String is
begin
return Self.Name;
end Get_name;
procedure Set_name (Self : access Object; To : in CORBA.Wide_String) is
begin
Self.Name := To;
end Set_name;
function Get_surname (Self : access Object) return CORBA.Wide_String is
begin
return Self.Surname;
end Get_surname;
procedure Set_surname (Self : access Object; To : in CORBA.Wide_String) is
begin
Self.Surname := To;
end Set_surname;
function New_User (Name : in CORBA.Wide_String;
Surname : in CORBA.Wide_String)
return Object_Ptr
is
begin
return
new Users.User.Impl.Object'
(PortableServer.Servant_Base with
Name => name, Surname => surname);
end New_User;
end Users.User.Impl;
with CORBA;
with PortableServer;
with Users.User;
package Users.UserFactory.Impl is
type Object is new PortableServer.Servant_Base with private;
type Object_Ptr is access all Object'Class;
function create
(Self : access Object;
name : in CORBA.Wide_String;
surname : in CORBA.Wide_String)
return Users.User.Ref;
private
type Object is new PortableServer.Servant_Base with null record;
end Users.UserFactory.Impl;
with Ada.Characters.Conversions;
with Ada.Wide_Text_IO;
with CORBA.ORB;
with PortableServer.POA.Helper;
with Globals;
with Users.User.Impl;
with Users.User.Helper;
with Users.UserFactory.Skel;
-- Осуществляем подключение файла скелетона - специального кода для
-- преобразования запростов в вызовы подпрограмм.
package body Users.UserFactory.Impl is
function create
(Self : access Object;
name : in CORBA.Wide_String;
surname : in CORBA.Wide_String)
return Users.User.Ref
is
Root_POA : PortableServer.POA.Local_Ref;
Result : Users.User.Ref;
begin
-- Получение ссылки на корневой объектный адаптер.
Root_POA :=
PortableServer.POA.Helper.To_Local_Ref
(CORBA.ORB.Resolve_Initial_References
(CORBA.ORB.To_CORBA_String ("RootPOA")));
-- Создание объекта и объектной ссылки на этот объект.
Result :=
Users.User.Helper.To_Ref
(PortableServer.POA.Servant_To_Reference
(Root_POA,
PortableServer.Servant
(Users.User.Impl.New_User (name, surname))));
-- Вывод на экран сформированной объектной ссылки.
Ada.Wide_Text_IO.Put_Line
("User ("
& CORBA.To_Wide_String (name)
& ", "
& CORBA.To_Wide_String (surname)
& ") created. IOR '"
& Ada.Characters.Conversions.To_Wide_String
(CORBA.To_Standard_String
(CORBA.Object.Object_To_String (Result)))
& "'");
-- Добавление в список пользователей.
Globals.User_Vectors.Append (Globals.Users, Result);
return Result;
end create;
end Users.UserFactory.Impl;
with CORBA;
with PortableServer;
package Users.UserFinder.Impl is
type Object is new PortableServer.Servant_Base with private;
type Object_Ptr is access all Object'Class;
function by_name
(Self : access Object;
name : in CORBA.Wide_String)
return Users.UserSequence;
private
type Object is new PortableServer.Servant_Base with null record;
end Users.UserFinder.Impl;
with Globals;
with Users.User;
with Users.UserFinder.Skel;
-- Осуществляем подключение файла скелетона - специального кода для
-- преобразования запростов в вызовы подпрограмм.
package body Users.UserFinder.Impl is
function by_name
(Self : access Object;
name : in CORBA.Wide_String)
return Users.UserSequence
is
use type CORBA.Wide_String;
use type Globals.User_Vectors.Cursor;
Result : Users.UserSequence;
Cursor : Globals.User_Vectors.Cursor
:= Globals.User_Vectors.First (Globals.Users);
begin
while Cursor /= Globals.User_Vectors.No_Element loop
if Globals.User_Vectors.Element (Cursor).Get_name = name then
Users.Append
(Result,
Users.User.Convert_Forward.To_Forward
(Globals.User_Vectors.Element (Cursor)));
end if;
Globals.User_Vectors.Next (Cursor);
end loop;
return Result;
end by_name;
end Users.UserFinder.Impl;
|
|