Вечная жизнь. Неуязвимость объектной ссылки

Вадим Годунко <vgodunko@gmail.com>, 2007–2008 г.

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

Сначала будет необходимо настроить ORB и POA таким образом, что бы объектные ссылки не теряли свою актуальность после перезапуска сервера. Поскольку корневой POA не позволяет изменять его характеристики потребуется создать собственный объектный адаптер. CORBA позволяет создавать любое количество POA для удобства организовывая их в иерархию. При создании POA необходимо указывать его имя, которое должно быть уникальным среди потомков одного родительского адаптера.

Добавим в главную подпрограмм создание собственного объектного адаптера и изменим реализацию фабрики для использования этого адаптера.

with Ada.Containers.Vectors;
with PortableServer.POA;
with Users.User;

package Globals is

   package User_Vectors is
     new Ada.Containers.Vectors (Positive, Users.User.Ref, Users.User."=");

   Users    : User_Vectors.Vector;
   User_POA : PortableServer.POA.Local_Ref;

end Globals;
with Ada.Text_IO;

with CORBA.Object;
with CORBA.ORB;
with CORBA.Policy;
with PortableServer.POA.Helper;
with PortableServer.POAManager;

with PolyORB.Setup.No_Tasking_Server;
--  Конфигурирование PolyORB для работы в режиме обычного многозадачного
--  сервера.

with Globals;
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
         Policies : CORBA.Policy.PolicyList;

      begin
         Globals.User_POA :=
           PortableServer.POA.Local_Ref
            (PortableServer.POA.Create_POA
              (Root_POA,
               CORBA.To_CORBA_String ("UserPOA"),
               PortableServer.POA.Get_The_POAManager (Root_POA),
               Policies)); 
      end;

      --  Создание объекта-фабрики и объектной ссылки на этот объект.

      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;
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
      --  Создание объекта и объектной ссылки на этот объект.

      Result :=
        Users.User.Helper.To_Ref
         (PortableServer.POA.Servant_To_Reference
           (Globals.User_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;

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

Имея в наличии собственный объектный адаптер можно приступать к его настройке. Для отключения ограничения срока действия объектных ссылок временем работы сервера необходимо указать значение PERSISTENT для политики Lifespan объектного адаптера. Доработаем код создания объектного адаптера соответствующим образом:

with Ada.Text_IO;

with CORBA.Object;
with CORBA.ORB;
with CORBA.Policy;
with PortableServer.LifespanPolicy;
with PortableServer.POA.Helper;
with PortableServer.POAManager;

with PolyORB.Setup.No_Tasking_Server;
--  Конфигурирование PolyORB для работы в режиме обычного многозадачного
--  сервера.

with Globals;
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
         Policies : CORBA.Policy.PolicyList;
         Lifespan : PortableServer.LifespanPolicy.Ref
           := PortableServer.POA.Create_Lifespan_Policy
               (PortableServer.PERSISTENT);

      begin
         CORBA.Policy.IDL_SEQUENCE_Policy.Append
          (Policies, CORBA.Policy.Ref (Lifespan));

         Globals.User_POA :=
           PortableServer.POA.Local_Ref
            (PortableServer.POA.Create_POA
              (Root_POA,
               CORBA.To_CORBA_String ("UserPOA"),
               PortableServer.POA.Get_The_POAManager (Root_POA),
               Policies)); 
      end;

      --  Создание объекта-фабрики и объектной ссылки на этот объект.

      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;

И остался последний шаг — настройка ORB. Настройка ORB сводится к указанию фиксированной точки доступа. Поскольку у нас используется транспортный протокол TCP/IP необходимо указать адрес и порт в файле polyorb.conf:

##  Фиксация точки доступа.
[iiop]
polyorb.protocols.iiop.default_addr=127.0.0.1
polyorb.protocols.iiop.default_port=6543

##  Управление точками доступа.

[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

Перезапуская сервер и сравнивая создаваемые объектные ссылки объектов‐пользователей, можно убедиться, что теперь каждый раз объектная ссылка имеет одну и ту же «расшифровку», выполненную программой po_catref (нужно заметить, что текстовое представление объектных ссылок совершенно не обязательно будет совпадать; это объясняется наличием в формате ссылки незначаших позиций, заполняющихся мусором).