3. Ada-95 — przetwarzanie rozproszone

Przed startem programu należy uruchomić usługę nazewniczą:

po_cos_naming

Usługa ta zwróci IOR, który należy ustawić jako wartość zmiennej środowiskowej POLYORB_DSA_NAME_SERVICE, np.:

export POLYORB_DSA_NAME_SERVICE=corbaloc:iiop:1.2@150.254.30.38:40941/NameService/000000024fF0000000080000000

3.1. Przykład zdalnego prodprogramu

Specyfikacja pakietu (rci.ads):

package RCI is
   pragma Remote_Call_Interface;

   type Wpis is record 
      numer: Positive;
      nazwa: String(1..10);
   end record;

   procedure Wstaw(p: in Wpis);
   function Nazwa(n: in Positive) return String;
end RCI;

Implementacja pakietu (rci.adb):

with Ada.Text_IO; use Ada.Text_IO;

package body RCI is
   Max: constant Positive := 100;
   wpisy: array (1..Max) of Wpis;

   procedure Wstaw(p: in Wpis) is
   begin
      wpisy(p.numer) := p;
      -- Put_line(Positive'Image(p.numer) & ". " & p.nazwa);
   end;

   function Nazwa(n: in Positive) return String is
   begin
      return wpisy(n).nazwa;
   end;
end RCI;

Przykład wywołania zdalnej procedury (rcall.adb):

with Ada.Text_IO, RCI;
use  Ada.Text_IO;

procedure rcall is
   p: RCI.Wpis;
begin
   p.numer := 1;
   p.nazwa(1..5) := "Darek";

   Put_line(p.nazwa);
   RCI.Wstaw(p);
   Put_line(RCI.Nazwa(1));
end rcall;

Opis konfiguracji (conf1.cfg):

configuration conf1 is 
   pragma Boot_Location ("tcp", "localhost:5678");
   pragma Starter (none);
   client, server: Partition;
   procedure rcall is in client;
begin
   server := (RCI);
end conf1;

Sposób kompilacji:

gnatdist conf1.cfg

Uwaga: nazwa pliku musi być taka sama jak nazwa opisanej w nim konfiguracji.

3.1.1. Pytania

  1. Czy można utworzyć 2 partycje udostępniacjące zdalnie pakiet RCI?
  2. Czy można uruchomić 2 razy partycję server?

3.2. Wyodrębnienie pakietu z opisem struktur danych

Pakiet zawiera tylko specyfikację i musi być skategoryzowany jako Pure (types.ads).

package Types is
   pragma Pure;
   Max_Name: constant Positive := 10;

   type Wpis is record 
      numer: Positive;
      nazwa: String(1..Max_Name);
   end record;
end Types;

Proszę zwrócić uwagę na obsługę wyjątków, np. wywołując procedurę zdalną z jakąś dużą wartością w polu numer rekordu-parametru (rcall.adb — wersja 2):

with Ada.Text_IO, RCI, Types;
use  Ada.Text_IO;

procedure rcall is
   p: Types.Wpis;
begin
   p.numer := 150;
   p.nazwa(1..5) := "Darek";

   Put_line(p.nazwa);
   RCI.Wstaw(p);
   Put_line(RCI.Nazwa(1));
end rcall;

3.3. Przykład procedury asynchronicznej

Różnica jest w kodzie występuje tylko w specyfikacji (rci.ads — wersja asynchroniczna):

with Types; use Types;

package RCI is
   pragma Remote_Call_Interface;

   procedure Wstaw(p: in Wpis);
   pragma Asynchronous(Wstaw);

   function Nazwa(n: in Positive) return String;
end RCI;

3.3.1. Pytania

  1. Czy tym razem przekazywany jest wyjątek?

3.4. Przykład procedury zwrotnej

Dodatkowy pakiet kategorii Remote_Call_Interface (callback.ads)

package Callback is
   pragma Remote_Call_Interface;
   procedure Return_key(key: in Positive);
end Callback;

i jego przykładowa implementacja callback.adb.

W przypadku poniższego wywołania procedura zwrotna wiązana jest statycznie, tzn. indentyfikowana jest jednoznacznie już w kodzie źródłowym i znana kompilatorowi (rci.adb — wersja z wywołaniem zwrotnym):

with Ada.Text_IO; use Ada.Text_IO;
with Callback;

package body RCI is
   Max: constant Positive := 100;
   wpisy: array (1..Max) of Wpis;

   procedure Wstaw(p: in Wpis) is
   begin
      wpisy(p.numer) := p;
      Put_line(Positive'Image(p.numer) & ". " & p.nazwa);
      Callback.Return_key(p.numer);
   end;

   function Nazwa(n: in Positive) return String is
   begin
      return wpisy(n).nazwa;
   end;
end RCI;

W opisie konfiguracji pakiet procedur zwrotnych jest w partycji klienta (conf6.cfg):

configuration conf6 is 
   pragma Boot_Location ("tcp", "localhost:5678");
   pragma Starter (none);
   client, server: Partition;
   procedure rcall is in client;
begin
   server := (RCI);
   client := (Callback);
end conf6;

3.5. Przykład wiązania dynamicznego

Do procedury zdalnej przekazywany jest wskaźnik (zdalny) na procedurę zwrotną. Typ wskaźnikowy musi być zdefiniowany w jednostce kategorii Remote_Call_Interface (callback.ads — def. zdal. wsk. na proc.)

package Callback is
   pragma Remote_Call_Interface;
   procedure Return_key(key: in Positive);
   type Callback_Procedure is access procedure (key: in Positive);
end Callback;

Przykład wywołania procedury zdalnej (rcall.adb — przekazanie wsk. na proc. zwrotną):

with Ada.Text_IO, RCI, Types;
use  Ada.Text_IO;
with Callback;

procedure rcall is
   p: Types.Wpis;
begin
   p.numer := 1;
   p.nazwa(1..5) := "Darek";

   Put_line(p.nazwa);
   RCI.Wstaw(p, Callback.Return_key'access);
   Put_line(RCI.Nazwa(1));
end rcall;

Przykład wywołania procedury zwrotnej (rci.adb — wywołanie z wiąz. dynamicz.):

with Ada.Text_IO; use Ada.Text_IO;

package body RCI is
   Max: constant Positive := 100;
   wpisy: array (1..Max) of Wpis;

   procedure Wstaw(p: in Wpis; cb_proc: in Callback_Procedure) is
   begin
      wpisy(p.numer) := p;
      Put_line(Positive'Image(p.numer) & ". " & p.nazwa);
      cb_proc(p.numer);
   end;

   function Nazwa(n: in Positive) return String is
   begin
      return wpisy(n).nazwa;
   end;
end RCI;

3.5.1. Pytania

  1. Czy można utworzyć 2 partycje typu klient?
  2. Czy można uruchomić kilka razy partycję klient?

3.6. Przykład zdalnego obiektu

Przykład definicji zdalnego obiektu (remote_key.ads):

with Types; use Types;

package Remote_Key is
   pragma Remote_Types;

   type Remote_Key_Type is new Key_Type with private;
   procedure Return_key(key: access Remote_Key_Type; value: in Positive);

   type Remote_Key_Reference is access all Remote_Key_Type'Class;
   -- pragma Asynchronous(Remote_Key_Reference);
private
   type Remote_Key_Type is new Key_Type with null record;
end Remote_Key;

Implementacja procedury Return_key sprowadza się do podstawienia wartości parametru w odpowiednie pole rekordu i wyświetlenia komunikatu (remote_key.adb)

Definicja typu Remote_Key_Type oparta jest na definicji rekordu znakowanego Key_Type w pakiecie Types (types.ads z typem znakowanym, types.adb).

Sam obiekt typu Remote_Key_Type tworzony jest w normalnym pakiecie Remote_Object (remote_object.ads).

Przykłady użycia obiektu zdalnego są w plikach (rcall.adb z przkaz. wsk. na zdal. obiekt , rci.ads z odniesieniem do zdal. obiektu, rci.adb z odniesieniem do zdal. obiektu)

Konfiguracja uwzględnia fakt, że może być wielu klientów. Wyodrebnione zostały 2 rodzaje partycji client — jedna z zasadniczą procedurą główną (i tym samym boot serwerem), a druga z alternatywną procedurą główną (conf7.cfg):

configuration conf7 is 
   pragma Boot_Location ("tcp", "localhost:5678");
   pragma Starter (none);
   client1, client2, server: Partition;
   for server'Termination use Global_Termination;
   procedure rcall is in client1;
   for client1'Termination use Deferred_Termination;
   for client2'Main use rcall;
   for client2'Termination use Local_Termination;
   -- for client2'Allow_Light_PCS use False;
begin
   server := (RCI);
   -- client1 := (Callback);
   -- client2 := (Callback);
end conf7;