CORBA

– Це набір специфікацій, що виникає в результаті самого широкого обговорення накопичених реальних проблем, в якому беруть участь і розробники і споживачі технологій. У результаті такого обговорення створюється документ, що пропонує рішення питань, що розглядаються на рівні існуючих технологій і технологій найближчої перспективи. Перевагою випереджаючої розробки специфікації в порівнянні з реалізацією є можливість для незалежних розробників створювати потенційно сумісні продукти, не обмежуючи свободи вибору мов, ОС, апаратних платформ, і не диктуючи вибору конкретного технологічного рішення.


Альтернативні підходи, найбільш яскраво виражені в політиці Microsoft і Sun, не відповідають сучасним тенденціям розвитку технологій, згідно з якими диктат одного виробника (хоча б і з самими кращими намірами) загалом, створює більше проблем, ніж вирішує. Тут маються на увазі не тільки технології. Прикладом цього служить ОС Windows, яка має більше користувачів, ніж всі інші разом узяті, і при цьому більшість розглядає цей вибір, як вимушений.


Будь-який приватний стандарт, підтримуваний окремим виробником (залишаючи осторонь питання про його відкритості) змушений дотримуватися історично склалася лінії розвитку, що рано чи пізно входить у суперечність з інтересами споживача.


Проблема монопольних стандартів полягає у завідомо протекціоністської політики власника стандарту, що виявляється на інших пов'язаних ринках, у випадку з Microsoft, це ОС. Посилене просування СОМ на платформі Windows робить перенесення цього стандарту на інші платформи економічно невигідним, змушуючи розробника вступати у свідомо програшну конкуренцію з Microsoft.


є концепцією, а не її реалізацією. Коли ми говоримо "COM", то розуміємо під цим скоріше набір конкретних засобів – елементів операційної системи, бібліотек, утиліт і т.п., що є складовою частиною того, що називається Microsoft Windows. Під терміном "" розуміється саме складна і розвинена концепція, сформульована на рівні спеціальної мови описів – IDL. Реалізації ж цієї концепції можуть сильно відрізнятися один від одного за різними критеріями, найбільш важливим в тому чи іншому випадку. VisiBroker (розробки Visigenic / Borland / Inprise / Corel) і Application Server, BEA WebLogic, Iona Orbix, Oracle Application Server і "картриджі" Oracle, IBM BOSS – всі ці продукти використовують ті чи інші можливості .


Під "стандартом" стосовно до розуміється те, що офіційно затверджено консорціумом OMG. Треба сказати, що це дуже високий рівень "легітимності", оскільки авторитет OMG в комп'ютерному світі надзвичайно високий. OMG являє собою некомерційну організацію, що є співтовариством розробників програмного забезпечення та його споживачів, що об'єднали свої зусилля для створення специфікацій цієї технології. На даний момент в OMG складається більш 800 членів, включаючи всіх скільки-небудь серйозних виробників програмного забезпечення (і навіть c недавнього часу Microsoft). Перша специфікація з'явилася в 1991 р. Нові можливості офіційно вважаються доданими в у момент затвердження відповідної специфікації. Як правило, в розробці специфікації беруть участь найбільші фахівці в даній області. Розробка реалізації – завдання конкретної фірми. Зазвичай від затвердження специфікації до появи високоякісної реалізації проходить досить багато часу – іноді кілька років. На даний момент стандартизовано відображення мови IDL на 6 мов програмування – Ada, C, C + +, Cobol, Java і Smalltalk. Існують також відображення на Pascal (точніше, Delphi), Perl, Python і ще декілька мов, але вони не є стандартизованими.


Об'єкти можна розглядати як екземпляри (instances) деякого метатіпа, причому і метатіп, і самі об'єкти існують поза зв'язку з конкретною програмою на конкретній мові. Цей метатіп в називається «інтерфейсом».


Інтерфейс


На щастя, для новачка в світі зрозуміти, що ж таке інтерфейс, не складає ніяких труднощів.


Інтерфейс в – це логічно згрупований набір методів і атрибутів. Кожному інтерфейсу присвоюється ім'я, унікальне в межах однієї розподіленої системи. На відміну від СОМ в немає бінарного стандарту інтерфейсів. Замість цього існує стандартна мова описів IDL. Так вже вийшло, що мови з назвою IDL існують в трьох різних технологіях – OSF / DCE, Microsoft / COM і OMG / . Ці мови багато в чому схожі, оскільки призначені для одного і того ж, але OMG / IDL дещо відрізняється від своїх «однофамільців».


За його основу був узятий мову C + + (його описова частина і директиви препроцесора), тому читач, знайомий з C + +, при роботі з IDL буде відчувати себе цілком комфортно.


Ось приклад оголошення інтерфейсів мовою IDL:







exception MyException {};
interface MyBaseInterface


   long MyMethod_1(in long i, out string str);
   void MyMethod_2 () raises (MyException);
};
interface MyDerivedInterface : MyBaseInterface {
    octet MyMethod_3 (inout double d);
};


На даний момент останньою стандартом є стандарт версії 2.3. У ньому поняття «об'єкт» і «інтерфейс» пов'язані, так би мовити, ставленням «один до одного» – один об'єкт не може підтримувати декілька інтерфейсів. У стандарті 3.0, прийняття якого очікується до кінця 2000 р, повинна з'явитися можливість створення об'єктів, що підтримують кілька інтерфейсів.


За допомогою наведеного вище прикладу визначення інтерфейсу (і, природно, певного програмного коду) ви можете, припустимо, створити 5 об'єктів типу MyBaseInterface і 10000 об'єктів MyDerivedInterface. Кожен з цих об'єктів зіставлений зі своїм типом і, крім цього, має свій унікальний ідентифікатор.


Ще раз повторимо – створення вищевказаних 10005 об'єктів у загальному випадку ніяк не пов'язане з «захопленням» ні ресурсів комп'ютера (в першу чергу пам'яті), ні мережевих ресурсів.


Сервант


Отже, ви можете створити -об'єкт і навіть встановити з ним зв'язок. У загальному випадку цього зовсім недостатньо, щоб використовувати його в конкретній програмі. Функціональність -об'єкта недоступна для клієнта до тих пір, поки в програмі (серверному додатку) не створений об'єкт, який дозволяє отримати доступ до методів, оголошеним в IDL-інтерфейсі. Цей об'єкт (реалізований на C + +, Java, C, Cobol, Ada, Smalltalk або деяких інших мовах) і називається «сервантом».


Звичайно, в залежності від використовуваної мови програмування, серванти реалізуються по-різному. Для об'єктно-орієнтованих мов сервант є екземпляром (instance) деякого класу, методи якого реалізують потрібну функціональність. Такий клас часто називають «класом реалізації».


За час існування -об'єкта з ним можна порівнювати безліч різних реалізацій сервантів (але не більше одного за раз). Більше того, вони можуть утримуватися в адресному просторі різних додатків. Ці програми можуть бути навіть запущені на різних комп'ютерах.


Часто кажуть, що сервант є «інкарнацією» -об'єкта. Зв'язок між сервантами та -об'єктами є хоч і строго формалізованої, але дуже гнучкою. Сервант може бути створений раніше чи пізніше -об'єкта; один сервант може «обслуговувати» як один, так і декілька (іноді сотні тисяч і мільйони) -об'єктів. Явна поділ циклів життя -об'єктів і їх сервантів (а саме серванти споживають реальні ресурси) – один із стовпів, на яких базується дуже висока масштабованість -додатків.


Об'єктна посилання


Єдина складність, пов'язана з розумінням сенсу терміну «об'єктна посилання», полягає в тому, що він використовується в двох різних значеннях.


Є об'єктна посилання «світу », яка представляє собою закодовану інформацію про -об'єкт. Вона включає ім'я хоста, порту TCP / IP (або координати репозитарію реалізації), звичайно ж, унікальний ідентифікатор даного -об'єкта і безліч іншої інформації, що дозволяє клієнту встановити зв'язок із серверним об'єктом через кордони мов програмування, операційних систем і апаратних платформ. Операції з об'єктної посиланням неможливі для клієнта, за винятком того, що клієнт може перетворити її в рядок і записати у файл або базу даних. Згодом хто завгодно може вважати такий рядок і перетворити її знову в об'єктну посилання.


В іншому розумінні «об'єктна посилання» – це змінна тієї чи іншої мови програмування, за допомогою якої клієнт здійснює виклик вилучених методів. У наступних розділах будуть наведені приклади отримання та використання такої об'єктної посилання. Надалі всі згадки об'єктних посилань відносяться саме до цього, другого, типу об'єктних посилань.


Концептуально змінна типу «об'єктна посилання» є покажчиком на так званий «proxy-об'єкт», який існує на стороні клієнта і забезпечує виконання віддалених викликів. Сам proxy-об'єкт зроблений недоступним для програміста; пов'язано це з тим, що його створення – завдання не клієнтського додатка, а самого ORB'а. Логічно з кожним proxy-об'єктом зіставлено окрема об'єктна посилання, і під копіюванням об'єктної посилання слід розуміти створення як нового proxy-об'єкту, так і налаштованого на нього нового «дороговказу». Зрозуміло, в реальних реалізаціях фізичного копіювання proxy-об'єкту не відбувається – як завжди в таких випадках, використовується механізм лічильника посилань.


Дуже важливо чітко розуміти, що копіювання (або знищення) об'єктних посилань на стороні клієнта впливає виключно на клієнтську програму. Неправильне ведення лічильника посилань у самому гіршому випадку призведе до продовження фізичного існування в клієнтському додатку непотрібного proxy-об'єкту. Ніякого відношення до серверного об'єкта ці дії не можуть мати в принципі. І створення, і знищення сервантів або серверних -об'єктів – завдання серверного додатку. Філософія полягає в тому, щоб клієнт посилав повідомлення «встановити зв'язок з існуючим об'єктом» і «розірвати з ним зв'язок», а не «створити серверний об'єкт» і «знищити його». Зрозуміло, клієнт може ініціювати створення Corba-об'єктів викликавши у видаленого об'єкту спеціально передбачений для цього програмістом (автором Об) метод.


Створення найпростішого об'єкта та його використання


Як не важливо розуміння теоретичних аспектів , все ж таки приклад використання у багатьох випадках здатний сказати більше, ніж самі розлогі міркування. В якості демонстрації етапів створення -додатки напишемо найпростіший приклад. Сервер створює об'єкт, який реалізує операцію складання двох цілих чисел. Клієнт встановлює зв'язок з серверним об'єктом, а потім викликає цей його єдиний метод, виводячи результат на екран. У прикладі використовується мову C + +.


Перший етап створення -програми – написання всіх необхідних IDL-декларацій. У нашому випадку IDL-код може виглядати так:






interface MyInterface {
   long Summa (in long op1, in long op2);
};

Наступний крок – це генерація файлів на стороні клієнта і сервера з допомогою компілятора idl2cpp. В якості входу компілятор отримує список idl-файлів. У нашому випадку це єдиний файл, що містить вищенаведене опис. Для файлу з ім'ям, наприклад, SimpleIDL.idl згенерують файли SimpleIDL_c.hh, SimpleIDL_c.cpp (для використання на стороні клієнта) і SimpleIDL_s.hh, SimpleIDL_s.cpp (Для використання на стороні сервера).


Створення серверного додатка


Файли _s .* містять код, який дозволяє зв'язати серверний додаток з . Для нас найбільший інтерес представляє згенерований клас POA_MyInterface. Цей клас містить оголошення чисто віртуальної (Абстрактної) функції Summa:






class POA_MyInterface : …
{
public:
   …
virtual ::Long Summa(::Long _op1,
                          ::Long _op2)
throw(::SystemException) = 0;
   …
};

Оскільки клас POA_MyInterface є тільки основою для серверного додатка, його часто називають «скелетом» або навіть «скелетоном» (skeleton).


Очевидно, що програмісту необхідно створити похідний від нього клас, в якому функція Summa була б визначена. Це можна зробити, наприклад, так:






class MyInterfaceImpl : public POA_MyInterface
{
public:
   MyInterfaceImpl () {}
   ::Long Summa(::Long _op1,
                     ::Long _op2)
         throw(::SystemException);
};

::Long MyInterfaceImpl::Summa(::Long _op1,
                                   ::Long _op2)
throw(::SystemException)
{
   return _op1 + _op2;
}

Клас реалізацій MyInterfaceImpl часто створюється автоматично, наприклад, за допомогою експертів, що входять до складу Borland C + + Builder або Java Builder.


Тепер залишилося написати код функції main ():






#include <fstream.h>
#include <corba.h>

#include “MyInterfaceImpl.h”


#pragma argsused
main(int argc, char* argv[])
{
   try
   {
/ / Ініціалізація взаємодії з
      ::ORB_var orb =
        ::ORB_init(argc, argv);
/ / Створення серванта майбутнього -об'єкта
        MyInterfaceImpl* servant =
        new MyInterfaceImpl;
/ / Створення тимчасового (transient)
/ / -об'єкта та отримання об'єктної посилання
        ::Object_ptr oRef = servant->_this();
/ / Перетворення об'єктної посилання в рядок
        ::String_var str =
        orb->object_to_string (oRef);
/ / Запис в файл
        ofstream oref_file (“MyORef.ior”);
        oref_file.write (str, strlen(str)+1);
        oref_file.close();
        cout << “Waiting for client requests…”;
/ / Цикл очікування запитів клієнтів
        orb->run();
   }
   catch(const ::Exception& e)
   {
cerr << e << endl;
return(1);
   }
   return 0;
}

Деякі пояснення. Створення серверного об'єкта за допомогою методу _this () застосовується досить рідко. Одержуваний таким чином об'єкт має сукупність характеристик, вкрай ускладнюють його використання. У розділі, присвяченому об'єктним адаптерам, буде розказано, як створювати «нормальні» -об'єкти.


Результатом виклику методу _this () є об'єктна посилання. Тип MyInterface визначає proxy-об'єкт, MyInterface_ptr (або MyInterface_var) – покажчик на нього. Це перший вид об'єктної посилання – на рівні додатки.


Друга об'єктна посилання – посилання рівня ORB – з'являється в результаті її перетворення до рядку з наступним записом цього рядка у файл. Ви можете ознайомитися з вмістом цього файлу відразу після запуску серверного додатку.


Об'єктна посилання записується у файл, звідки її може вважати додаток-клієнт. Зрозуміло, цей спосіб швидше демонструє принцип організації зв'язку між клієнтом і сервером, ніж представляє яку-небудь практичну цінність.


Зверніть увагу на те, що одне і теж додаток може бути як клієнтом, так і сервером – в цьому плані не накладає ніяких обмежень.


Створення клієнтської програми


Файли _c .* містять все необхідне для взаємодії клієнтського додатка з серверним через інфраструктуру . Нічого дописувати не треба – використовуйте це код «як є». Часто або сукупність цих файлів, або деякі з них називають «заглушкою» (stub).






//————————————–
#include <fstream.h>
#include <corba.h>

#include “SimpleIDL_c.hh”


#pragma argsused
main(int argc, char* argv[])
{
int op1, op2;
try
{
if (argc == 3)
{
op1 = atoi (argv[1]);
op2 = atoi (argv[2]);
}
else
{
cout <<
“Command string: client arg1 arg2
“;
return 1;
}
ifstream inp_file (“MyORef.ior”);
if (!inp_file)
{
cout << “File MyORef.ior not found.
“;
return 1;
}
/ / Читання об'єктної посилання в строковому
/ / Вигляді з файлу
char str[1000];
inp_file >> str;
inp_file.close();
/ / Ініціалізація взаємодії з
::ORB_var orb =
::ORB_init(argc, argv);
/ / Отримання об'єктної посилання перетворенням
/ / З рядка
::Object_var obj =
orb->string_to_object (str);
MyInterface_var oRef =
MyInterface::_narrow (obj);
if (::is_nil(oRef))
{
cout << “Failure during getting of object”
” reference
“;
}
else
{
/ / Виклик віддаленого методу
int res = oRef->Summa (op1, op2);
cout << op1 << ” + ” << op2 << ” = “
<< res << endl;
}
}
catch(const ::Exception& e)
{
cerr << e << endl;
return(1);
}
return 0;
}

Ось, власне, і все.


Зауважимо, що цей приклад при використанні C + + Builder 4 / 5 можна б написати з ще меншою кількістю коду, але для роботи нам було б потрібно попередньо запустити якийсь компонент , що поставляється разом з VisiBroker – так званий «smart agent». Розмова про нього ще попереду.


Створення або клієнта, або сервера, або їх обох на іншій мові просто зажадало б використання не компілятора idl2cpp, а компіляторів idl2java, idl2ada і т.д. Зрозуміло, немає ніяких перешкод для написання, наприклад, сервера на C + + для SPARC / Solaris, а клієнта – на Java під Windows. Врахування особливостей архітектур (наприклад, різного порядку байтів у машинному слові) відбувається автоматично – За це відповідає ORB.


Управління об'єктами


Створений у попередньому прикладі об'єкт (не сервант, а сам -об'єкт) є об'єктом тимчасовим. Це означає, що він не може існувати довше, ніж існує компонент , що його створив. У розглянутому прикладі цей компонент явно не був присутній у програмі, і такий спосіб створення -об'єкта часто називають «неявним». У реальних програмах більшість -об'єктів створюється іншим шляхом. Даний розділ і присвячений розгляду пов'язаних з цією темою питань.


Об'єктні адаптери


Компонент , який відповідає за створення -об'єктів, їх сервантів, підтримує зв'язок між ними і бере участь у доставці виклику клієнта потрібного серванті, називається об'єктним адаптером.


Стандарт дозволяє мати і використовувати (причому одночасно) кілька різних об'єктних адаптерів. В даний час існують два стандартних об'єктних адаптера – BOA (Basic Object Adapter) і POA (Portable Object Adapter). Використання BOA визнано застарілим, тому що це не дозволяє забезпечити переносимість серверних -додатків, і ми про нього говорити не будемо.


POA


У реальних -додатках використовується деревоподібна ієрархія об'єктних адаптерів. У корені її знаходиться так званий Root POA – об'єктний адаптер за замовчуванням. Саме він створював наш -об'єкт у розглянутому раніше прикладі.


Програміст отримує доступ до Root POA c допомогою стандартного коду, що використовується в багатьох випадках:






::ORB_var orb = ::ORB_init(argc, argv);
::Object_var rpObj =
orb->resolve_initial_references(“RootPOA”);
PortableServer::POA_var rootPoa =
PortableServer::POA::_narrow(rpObj);

Чому практично завжди недостатньо RootPOA, і програмісти повинні створювати додаткові POA? Причина полягає в тому, що кожен POA створюється з певним набором властивостей, і після цього він здатний створювати об'єкти і серванти тільки певного виду – наприклад, тільки тимчасові або тільки «довгоживучі» (persistent).


Дочірні POA створюються за допомогою звернення до вже створених POA як до фабрик. Майте на увазі, що дочірній POA не успадковує властивостей свого базового POA – набір властивостей для кожного створюваного об'єктного адаптера потрібно вказувати явно. Наприклад, якщо ви хочете створювати «довгоживучі» об'єкти, то спочатку потрібно створити відповідний POA.


Перед створенням дочірніх POA бажано (хоча і не обов'язково) створити так званий «менеджер» POA. Він відповідає за розподіл клієнтських запитів між сервантами, що знаходяться під управлінням різних POA, а також за управління їх (POA) циклом життя. Фабрикою такого менеджера може бути Root POA. При створенні дочірніх об'єктних адаптерів ви вказуєте менеджер POA в якості аргументу. Якщо ви не створили свій менеджер і замість його імені при виклику методу створення POA вказали nil, то буде неявно створений і використаний менеджер за умовчанням.






PortableServer:: POAManager_var poaMngr = rootPoa-> the_POAManager ();
::PolicyList policyList;
policyList.length(1);
policyList[0] =
rootPoa->create_lifespan_policy(PortableServer::PERSISTENT);
PortableServer::POA_var myPOA = rootPoa->create_POA(
“MyPOA”, poaMngr, policyList);

Процес знищення об'єктних адаптерів відбувається у певному порядку – спочатку дочірні POA, потім їх «батьки».


Створення об'єкта з використанням POA


Наведемо приклад створення об'єкта з використанням myPOA. Як вже говорилося, з кожним -об'єктом потрібно зіставити «ключ» – ідентифікатор, який дозволяє однозначно ідентифікувати цей об'єкт. Давайте поставимо це ідентифікатор явно. Для цього викличемо метод, який дозволяє створити цей ідентифікатор на основі рядка: 8






PortableServer::ObjectId_var objID =
PortableServer::string_to_ObjectId (“MyObject”);

Наступні дві команди створюють сервант, а потім і -об'єкт із зазначеним ObjectID






MyInterfaceImpl servant;
myPOA->activate_object_with_id (objID, &servant);

Нарешті, для початку обробки запитів від клієнта ви повинні активізувати менеджер POA:






poaMngr->activate();

Практику, коли для кожного -об'єкта під час запуску програми створюється свій сервант, не можна визнати вдалою – так можна «з'їсти» будь-яку кількість ресурсів. Раніше говорилося, що розробник може створювати -об'єкти і без створення сервантів. Зробити це дуже просто:






myPOA->create_reference_with_id(
objID, “IDL:MyInterface:1.0”);

Зіставити з таким об'єктом сервант можна пізніше, причому самими різними способами (про це буде розказано пізніше).


Тимчасові і довгоживучі об'єкти


Давайте тепер поговоримо про те, що таке «знищення» об'єкту і як ведуть себе тимчасові об'єкти.


У є команди створення об'єктів, але немає команди їх знищення. Зроблено це тому, що вкрай важко знайти конкретний компонент , який узяв би на себе «праця» надійного і безпечного нищення об'єктів. У результаті цього, під знищенням об'єкта розуміється деяка послідовність дій (або відсутність будь-яких дій), які призводять до того, що жоден клієнт за наявними у нього об'єктним посиланнях не може отримати доступ до -об'єкту.


Розглянемо, що відбувається у випадку тимчасового об'єкта, створеного раніше за допомогою виклику методу _this (). Об'єктна посилання на цей об'єкт, передана клієнту через файл, містить у собі ім'я хоста, на якому було запущено створило об'єкт додаток, використаний порт TCP / IP, унікальний (автоматично створений) ідентифікатор об'єкта і унікальний (автоматично створений) ідентифікатор POA, який теж є -об'єктом, хоча і з особливостями. Це означає, що клієнт може використовувати наявну у нього об'єктну посилання тільки до тих пір, поки серверний додаток запущено і в ньому «живе» створив об'єкт об'єктний адаптер.


При зупинці і наступному запуску цього ж додатка на тому ж комп'ютері буде створено новий -об'єкт – його власний ідентифікатор та ідентифікатор його POA будуть відрізнятися від тих, дані для яких перебувають у «старій» об'єктної посиланням. Це означає, що по ній отримати доступ до «старого» об'єкту в принципі неможливо. У цьому випадку і кажуть, що -об'єкт більше не існує. Клієнт може «викинути» наявну в нього об'єктну посилання – вона більше ніколи не знадобиться.


У разі використання довгоживучих об'єктів справа йде складніше. Навіть якщо об'єкт створений за допомогою POA, призначеного для створення і управління persistent-об'єктами, це не означає, що після зупинки серверного програми, клієнт зможе викликати віддалені методи за наявною у нього об'єктної посиланням. У найпростішому випадку, жодних проблем не буде, якщо серверний додаток знову запущено «вручну» на тому ж хості і з використанням того ж порту TCP / IP. Розгляд більш загального випадку виходить за рамки цієї статті. Автоматичний запуск серверів додатків буде розглянуто в розділі, присвяченому Репозитарії Реалізацій.


Властивості POA


Можливість явної вказівки того, чи є -об'єкт тимчасовим або довготривалим – це тільки одна із стандартних можливостей POA. Визначається вона (мовою IDL) наступним чином:






module PortableServer
{
enum LifeSpanPolicyValue { TRANSIENT, PERSISTENT };
interface LifeSpanPolicy : ::Policy
{
readonly attribute LifeSpanPolicyValue;
};

Ось список всіх інших:


Режим управління завданням ідентифікатора об'єкта (IdAssignmentPolicyValue). Можливі значення – USER_ID або SYSTEM_ID. У першому випадку ідентифікатор об'єкта задає сам користувач, у другому – він автоматично генерується POA.


Режим підтримки одним сервантом декількох -об'єктів (IdUniquenessPolicyValue). Можливі значення – UNIQUE_ID (один сервант є інкарнацією тільки одного -об'єкта) і MULTIPLE_ID (один сервант може обслуговувати декілька об'єктів).


Режим дозволу неявній активації (ImplicitActivationPolicyValue). Можливі значення – IMPLICIT_ACTIVATION (неявне створення -об'єкта, наприклад, за допомогою _this (), дозволено) і NO_IMPLICIT_ACTIVATION (Необхідно створювати -об'єкти явно).


Режим створення та управління сервантами (RequestProcessingPolicyValue). Тут потрібно дати більш докладні пояснення.


У принципі, можливі тільки два режими створення сервантів: серванти створюються в програмі чи явно (як в раніше розглянутих прикладах), або в процесі надходження клієнтських запитів – можливо, навіть для обслуговування одного-єдиного запиту. POA забезпечує підтримку обох режимів.


По-перше, POA може містити так званий Active Object Map (AOM), тобто масив покажчиків на вже створені серванти. «Індексом» цього масиву є значення Object ID. У цей масив можуть потрапляти як серванти, створені явно програмістом, так і серванти, динамічно створені самим об'єктним адаптером.


У випадку динамічного створення сервантів передбачено два окремих режиму – Activation-режим і Location-режим. Назви їх, на мій погляд, обрані дуже дивним чином. Activation-режим полягає в тому, що при вступі клієнтського запиту POA спочатку шукає підходящий сервант в AOM, і тільки якщо такий не знайдений, цей сервант динамічно створюється POA, а потім покажчик на нього поміщається в AOM. Location-режим (явно всупереч своїй назві) не «дивиться» у AOM – AOM взагалі не підтримується в цьому режимі – а створює сервант для обслуговування прийшов виклику, а потім знищує його.


Процес динамічного створення сервантів полягає в тому, що POA викликає деякі написані програмістом функції. Природно, такі функції необхідно зареєструвати в POA – для цього передбачені спеціальні команди.


Нарешті, передбачений якийсь допоміжний, але в деяких випадках дуже зручний режим – так званий «сервант за умовчанням». Суть цього режиму полягає в тому, що програміст явно створює один-єдиний сервант і реєструє його як сервант, який є інкарнацією всіх -об'єктів. Ось приклад ситуації, коли такий підхід цілком виправданий: для взаємодії з базою даних ви створюєте сотні, тисячі або мільйони -об'єктів – по одному на кожен запис, а потім при об'єднанні в один сервант, який не має свого стану, який обслуговує всі ці об'єкти. Стан кожного -об'єкта просто витягається з відповідного запису бази даних.


Отже, можливі значення опції RequestProcessingPolicyValue:



Приклад використання Activation-режиму


Спочатку необхідно створити клас, який буде містити функції створення і знищення серванта:






class MyInterfaceActivator_Impl : public
PortableServer::ServantActivator
{
public:
MyInterfaceActivator_Impl();
virtual PortableServer::Servant incarnate(
const PortableServer::ObjectId& oid,
PortableServer::POA_ptr poa)
throw(::SystemException,
ortableServer::ForwardRequest);
virtual void etherealize (
const PortableServer::ObjectId& oid,
PortableServer::POA_ptr poa,
PortableServer::Servant servant,
::Boolean cleanup_in_progress,
::Boolean remaining_activations)
throw (::SystemException);
};

Неважко здогадатися, що методи incarnate () і etherealize () оголошені як чисто віртуальні в стандартному класі PortableServer:: ServantActivator. Ваше завдання – створити їх реалізацію, наприклад, так:






PortableServer::Servant
MyInterfaceActivator_Impl::incarnate(
const PortableServer::ObjectId& oid,
PortableServer::POA_ptr poa)
throw(::SystemException,
PortableServer::ForwardRequest)
{
return new MyInterfaceImpl();
}

void MyInterfaceActivator_Impl::etherealize(
const PortableServer::ObjectId& oid,
PortableServer::POA_ptr poa,
PortableServer::Servant servant,
::Boolean cleanup_in_progress,
::Boolean remaining_activations)
throw (::SystemException)
{
delete servant;
}


Ми тут не будемо обговорювати, наприклад, ситуацію, при якій програміст явно створить кілька сервантів в стеку, а також з'ясування питання, коли викликається метод etherealize ().


Нижче приведений код, який створює POA з підтримкою необхідного режиму управління POA, два -об'єкта і реєструє раніше створений клас як менеджер сервантів (не плутати з менеджером POA!):






::ORB_var orb = ::ORB_init (argc, argv);
::Object_var rpObj =
orb->resolve_initial_references (“RootPOA”);
PortableServer::POA_var rootPoa =
PortableServer::POA::_narrow (rpObj);
PortableServer::POAManager_var poaMngr =
rootPoa->the_POAManager();
::PolicyList policyList;
policyList.length(3);
policyList[0] = rootPoa->create_lifespan_policy
(PortableServer::PERSISTENT);
policyList[1] =
rootPoa->create_request_processing_policy(
PortableServer::USE_SERVANT_MANAGER);
policyList[2] =
rootPoa->create_servant_retention_policy(
PortableServer::RETAIN);
PortableServer::POA_var myPOA =
rootPoa->create_POA (“MyPOA”, poaMngr,
policyList);
PortableServer::ObjectId_var objID_1 =
PortableServer::string_to_ObjectId (“MyObject_1”);
myPOA->create_reference_with_id (objID_1,
“IDL:MyInterface:1.0”);
PortableServer::ObjectId_var objID_2 =
PortableServer::string_to_ObjectId (“MyObject_2”);
myPOA->create_reference_with_id (objID_2,
“IDL:MyInterface:1.0”);
MyInterfaceActivator_Impl* manager =
new MyInterfaceActivator_Impl;
myPOA->set_servant_manager (manager);
poaMngr->activate();

Приклад використання Location-режиму

Location-режим має багато спільного з Activation-режимом; тим не менш, приведемо фрагменти коду відповідного прикладу:






class MyInterfaceLocator_Impl :
public PortableServer::ServantLocator
{
public:
MyInterfaceLocator_Impl();
virtual PortableServer::Servant preinvoke(
const PortableServer::ObjectId& oid,
PortableServer::POA_ptr poa,
const char* operation,
void*& cookie)
throw (::SystemException,
PortableServer::ForwardRequest);
virtual void postinvoke(
const PortableServer::ObjectId& oid,
PortableServer::POA_ptr poa,
const char* operation,
void* cookie,
PortableServer::Servant servant)
throw (::SystemException);
};
PortableServer::Servant
MyInterfaceLocator_Impl::preinvoke(
const PortableServer::ObjectId& oid,
PortableServer::POA_ptr poa,
const char* operation,
void*& cookie)
throw (::SystemException,
PortableServer::ForwardRequest)
{
cookie = new char[11];
strcpy(reinterpret_cast<char*>(cookie),
“Activation”);
return new MyInterfaceImpl();
}
void MyInterfaceLocator_Impl::postinvoke(
const PortableServer::ObjectId& oid,
PortableServer::POA_ptr poa,
const char* operation,
void* cookie,
PortableServer::Servant servant)
throw (::SystemException)
{
cout << reinterpret_cast<char*>(cookie) <<
” and deactivation” << endl;
delete cookie;
delete servant;
}

POA потрібно створювати з таким набором властивостей:






::PolicyList policyList;
policyList.length(3);
policyList[0] = rootPoa->create_lifespan_policy(
PortableServer::PERSISTENT);
policyList[1] =
rootPoa->create_request_processing_policy(
PortableServer::USE_SERVANT_MANAGER);
policyList[2] =
rootPoa->create_servant_retention_policy(
PortableServer::NON_RETAIN);
PortableServer::POA_var myPOA =
rootPoa->create_POA (“MyPOA”, poaMngr,
policyList);

/ / Створення об'єктів (як у попередньому прикладі)
MyInterfaceLocator_Impl* manager =
new MyInterfaceLocator_Impl;
myPOA->set_servant_manager (manager);

Приклад використання режиму з сервантом за замовчуванням


Код програми з сервантом за замовчуванням дуже простий. Тут немає ніяких callback-методів, і все, що потрібно зробити – це створити POA в потрібному режимі, потім єдиний сервант, а потім зареєструвати цей сервант:






::PolicyList policyList;
policyList.length(3);
policyList[0] = rootPoa->create_lifespan_policy(
PortableServer::PERSISTENT);
policyList[1] =
rootPoa->create_request_processing_policy(
PortableServer::USE_DEFAULT_SERVANT);
policyList[2] =
rootPoa->create_id_uniqueness_policy(
PortableServer::MULTIPLE_ID);
PortableServer::POA_var myPOA =
rootPoa->create_POA (“MyPOA”, poaMngr,
policyList);

/ / Створення об'єктів (як у попередньому прикладі)
MyInterfaceImpl* objImpl = new MyInterfaceImpl;
myPOA->set_servant (objImpl);

Використання лічильника посилань сервантів


У реальних складних додатках не рекомендується створювати і знищувати серванти так, як це було продемонстровано в попередніх прикладах, хоча такий підхід цілком можна використовувати для невеликих додатків. Проблема полягає в тому, що явна команда знищення серванта у вигляді






delete servant;

увазі, що цей же сервант не зареєстрований в інших POA та / або до нього немає звернень з інших потоків. Крім того, навіть у разі дотримання цих умов, можливі проблеми при спробі виконати цю команду всередині одного з методів об'єкта. Справа в тому, що запис про серванті в Active Object Map залишається до тих пір, поки не виконаний до кінця хоча б один метод цього об'єкта. Помилка може відбутися при наступній спробі видалення запису з Active Object Map, так як з нею вже не підтверджено реальний сервант.


Сам POA завжди вважає, що в програмі використовується зовсім інший підхід, а саме, ведення лічильника посилань сервантів. Хто ж реально цим займається?


Наш клас реалізації, якщо пам'ятаєте, успадковував клас POA_MyInterface, згенерований компілятором idl2cpp. У свою чергу, POA_MyInterface побудований на базі стандартного класу PortableServer:: ServantBase:






class POA_MyInterface : public virtual
PortableServer::ServantBase
{

}

У класі PortableServer:: ServantBase оголошені і реалізовані тривіальним чином функції _add_ref () і _remove_ref ():






class PortableServer::ServantBase
{

public:
virtual void _add_ref () {};
virtual void _remove_ref () {};

};

При спробі видалення серванта POA ЗАВЖДИ виконує команду _remove_ref (), яка логічно передбачає зменшення лічильника посилань на сервант з видаленням його при досягненні цим лічильником значення 0. Для стандартних методів – таких, як _this () – виконується виклик методу _add_ref (). Оскільки за замовчуванням ні _add_ref (), ні _remove_ref () не роблять нічого, ви можете не підозрювати про їх присутність.


Якщо ж ви хочете використовувати лічильник посилань на серванти, уникнувши тим самим згаданих на початку розділу проблем, ви можете в якості базового класу для POA_MyInterface замість PortableServer:: ServantBase вказати стандартний клас PortableServer:: RefCountServantBase:






class PortableSever_RefCountServantBase : public
PortableServer_ServantBase
{
public:

virtual void _add_ref ();
virtual void _remove_ref ();
};

У цьому класі реалізований реальний, а не фіктивний лічильник посилань. Потрібно мати при цьому на увазі, що ви зобов'язуєтеся, по-перше, створювати серванти тільки в динамічній пам'яті, а по-друге, при їх видаленні замість delete servant; завжди використовувати servant-> _remove_ref ().


Установка зв'язку між клієнтом і серверним об'єктом


Після знайомства з об'єктними посиланнями стало зрозуміло, що встановлення зв'язку між клієнтом і серверним об'єктом полягає в отриманні клієнтом об'єктної посилання на цей об'єкт. Звичайно, передача об'єктної посилання через файл, продемонстрована раніше, хоча і можливий, але, зрозуміло, не може вважатися хоч скільки-небудь зручним і універсальним способом.


Ще раз нагадаємо: у клієнт вважає, що всі необхідні серверні об'єкти вже існують, тому він (логічно) завжди використовує команду «знайти» і ніколи – команду «створити».


У застосовуються два основних стандартних способу, що дозволяють зробити серверний об'єкт доступним для клієнта, тобто, передати клієнту об'єктну посилання на цей об'єкт. Один з цих способів пов'язаний з використанням Сервісу Імен (Naming Service), другий – Трейдер-Сервісу (Trader Service).


Крім стандартних служб, багато виробників розробляють і поставляють свої власні (хоча і нестандартні, але часто дуже зручні) засоби пошуку. Для VisiBroker'а таким засобом є Location Service, який базується на використанні Smart Agent. Оскільки VisiBroker є однією з найпоширеніших (принаймні, в нашій країні) реалізацією ORB, ми коротко розглянемо і цей спосіб – Більше того, ми саме з нього і почнемо з простоти його використання.


Використання Inprise Location Service


Location Service представляє собою якусь програмну середовище, яке створюється в локальній мережі (або в сукупності з'єднаних між собою локальних мереж) з метою спрощення пошуку клієнтом потрібного серверного об'єкта. Для її використання потрібно:



Smart agent може:


Після того, як зв'язок встановлено, тобто клієнт отримав об'єктну посилання, починається «стандартна» , і Location Service, загалом, більше не потрібен, хоча ви і можете його використовувати, наприклад, для відображення довідкової інформації про існуючі -об'єкти.

При запуску smart agent'а використовується фіксований порт TCP. Для VisiBroker номер порту, який використовується за умовчанням, може бути заданий за допомогою спеціальних утиліт, і для зберігання його значення використовуються спеціальні змінні середовища. Для Windows це значення прописується ще і в реєстрі.


Якщо ви хочете, щоб ваш додаток явно використовувало той чи інший порт, ви можете використовувати значення за замовчуванням або явно вказати номер порту при запуску вашої програми, наприклад, так:






prompt> Server -Dvbroker.agent.port=14010

Стосовно до Location Service існує поняття «домен», тобто сукупність smart agent'ов і додатків, що використовують для зв'язку між собою один і той же порт. Зауважимо, що в одній локальній мережі можуть одночасно і незалежно один від одного існувати декілька доменів.


Як має виглядати код клієнтського і серверного додатку при використовуванні Location Service?


Перш за все, на стороні сервера розробник повинен вибрати режим реєстрації серверних об'єктів у Location Service. Можливі два варіанти, і для обох створюваний об'єкт повинен бути persistent-об'єктом.


Перший з них (цей режим використовується за умовчанням) реєструє не кожен об'єкт окремо, а тільки його POA. У цьому випадку додатково на стороні сервера нічого робити не треба, і код створення POA і об'єкта міг би виглядати так:






::PolicyList policyList;
policyList.length(2);
policyList[0] = rootPoa->create_lifespan_policy(
PortableServer::PERSISTENT);
PortableServer::POA_var myPOA =
rootPoa->create_POA (“MyPOA”, poaMngr, policyList);
MyInterfaceImpl servant;
PortableServer::ObjectId_var objID =
PortableServer::string_to_ObjectId (“MyObject”);
myPOA->activate_object_with_id (objID, &servant);
poaMngr->activate();

Клієнт може отримати об'єктну посилання наступним чином:






PortableServer::ObjectId_var objID =
PortableServer::string_to_ObjectId(“MyObject”);
MyInterface_var objRef =
MyInterface::_bind (“/MyPOA”, objID);

Ця версія методу _bind містить п'ять аргументів, з них два обов'язкових. Перший з них задає потрібний POA (POA розділяються символом'/'). Другий – ідентифікатор об'єкта.


Три необов'язкових аргументу дозволяють задати ім'я хоста, режим встановлення зв'язку і використовуваний ORB.


Другий спосіб – реєстрація не об'єктного адаптера, а кожного об'єкта окремо:






::PolicyList policyList;
policyList.length(2);
policyList [0] = rootPoa-> create_lifespan_policy (PortableServer:: PERSISTENT);
::Any any;
/ / BY_POA за замовчуванням
any <<= PortableServerExt::BY_INSTANCE;
policyList[1] = orb->create_policy(
PortableServerExt::BIND_SUPPORT_POLICY_TYPE, any);

/ / То ж, що і раніше


Код клієнта виглядає навіть простіше:






MyInterface_var objRef = MyInterface::_bind (“MyObject”);

У цьому випадку всі чотири аргументи – ім'я об'єкта, ім'я хоста, режим зв'язку і потрібний ORB – не є обов'язковими. При їх відсутності Location Service поверне посилання на перший-ліпший об'єкт, який реалізує інтерфейс MyInterface.


Перевагою Location Service є простота і зручність його використання. Крім того, він забезпечує деякі можливості розподілу навантаження між наявними серверами додатків, а також стійкість до збоїв. Особливо ефектно остання можливість реалізується у разі запуску кількох однакових серверів додатків, які використовують об'єкти без стану. У цьому випадку як «падіння» деяких з серверів додатків, так і «загибель» кількох smart agent'ов для клієнта залишаються просто непоміченими.


Використання Naming Service


Naming Service, на відміну від Location Service, є стандартним сервісом . Він дозволяє зіставляти з серверними об'єктами довільні імена. Таким чином, замість використання перетворених до строковому увазі об'єктних посилань та, в кращому випадку, строкових уявлень ідентифікаторів об'єктів (Object ID), програмісти використовують довільні і (бажано) осмислені імена. Тепер клієнт не повинен знати нічого про об'єкт, крім його імені та місцезнаходження примірника служби імен, який і зіставляє з ім'ям реальну об'єктну посилання.


Звичайно, не можна сказати, що це дуже гнучкий і зручний спосіб, але в багатьох випадках його цілком достатньо. У реальному житті такі підходи використовуються часто-густо – словники, енциклопедії, телефонні довідники (точніше, їх «білі» сторінки).


Що розуміється під «екземпляром» служби імен?


Це просто сервант деякого -об'єкта, який реалізує кілька стандартних інтерфейсів, IDL-декларації яких і складають -частина Naming Service. Інша частина – це (при використанні C + +) h-файли і бібліотеки, в яких зберігається код стандартних методів. Як і будь-який сервант, примірник Naming Service повинен бути створений і зіставлений з конкретним -об'єктом, тому для використання можливостей Naming Service вам необхідно запустити якесь додаток – фабрику відповідного об'єкта та його серванта.


Так як екземпляр Служби Імен сам є -об'єктом, то немає ніяких перешкод для того, щоб один такий екземпляр містив посилання на інший. Такі Служби часто називають «об'єднаними» (federated).


Цей об'єкт дозволяє побудувати струнку систему імен. У більшості случкаев така систему імен представляє з себе дереві або ліс, але впринципі вона може бути графом більш загального вигляду. Будь-яка з вершин цього графа (дерева) може розглядатися як корінь для початку пошуку. Naming Service не передбачає наявності спільного кореня – таких коренів може бути декілька. Взагалі кажучи, клієнт повинен знати, з якого кореня за ієрархією потрібно почати пошук; в процесі пошуку клієнт може отримати не тільки імена об'єктів, а й співставлений з кожним ім'ям короткий коментар у вигляді рядка. Можна уявити ситуацію, коли клієнт приймає рішення про те, який же, власне, об'єкт йому потрібен, на підставі цієї додаткової інформації, забезпечувана Сервісом іменування.


У загальному випадку структура, створювана за допомогою стандартних методів Naming Service, дуже схожа на файлову структуру. Імена об'єктів завжди є «листям» дерева. Можна провести наступну аналогію: кореневі контексти – це логічні диски, контексти імен – це каталоги, а імена об'єктів – це файли. Як і для файлової системи, справедливі наступне: контекст імен може містити довільне число інших контекстів і імен об'єктів, причому імена контекстів чи об'єктів можуть повторюватися, але тільки якщо повторювані імена знаходяться на різних шляхах.


На даний момент стандартом Naming Service є специфікація, затверджена в 1995Кг. Ви можете знайти її, як і всі інші специфікації, на сайті www.omg.org, в документі 97-12-10.pdf. Тим не менш, в самий найближчий час буде затверджена нова специфікація, і Naming Service буде перейменований в Interoperable Naming Service (INS). Його попередня специфікація міститься у файлі 98-10-11.pdf.


У зв'язку з тим, що INS є розширенням NS (за винятком так званих «бібліотек імен»), а також тому, що вже існують реалізації INS, ми у наведених прикладах будемо використовувати код в новому стилі.


Які ж переваги надає нова специфікація?


По-перше, вона дозволяє клієнту для доступу до екземплярів служб використовувати URL-імена.


По-друге, вона надає (поки досить примітивні) засоби управління навантаженням (так звані кластери імен) та забезпечення стійкості до збоїв.


По-третє, вона істотно підвищує зручність роботи з іменами.


По-четверте, передбачені стандартні засоби збереження (і відновлення) інформації, що міститься в екземплярі Служби Імен. Попередня специфікація просто не дозволяла мати в програмі рядок, що містить опис «шляху» від деякого контексту до імені об'єкта.


Дана стаття, природно, не ставить завдання докладного викладу INS – для цього треба було б чимало місця. Ми просто приведемо невеликий приклад. У цьому застосуванні створюється все той же об'єкт, який реалізує інтерфейс MyInterface, але клієнт отримує об'єктну посилання на нього за допомогою Naming Service.


Поставимо собі наступне завдання: ми створимо невелику ієрархію імен. Кореневий контекст містить контекст з ім'ям «OtherContext» і з коментарем «Context». Цей контекст, у свою чергу, містить посилання на потрібний нам серверний об'єкт. З цим об'єктом можна порівняти ім'я «NamedObject» з коментарем «Object Reference».






::Object_var nsv;
/ / Root Context в стилі INS
CosNaming::NamingContextExt_var rootN;
try
{
nsv = orb->resolve_initial_references(“NameService”);
rootN = CosNaming::NamingContextExt::_narrow(nsv.in());
if (::is_nil(rootN))
{
Cout <<"Не знайдено root контекст" <<endl;
/ / Обробка помилок пропущена
}

/ / Створення контексту імен в стилі NS – це
/ / Необхідно для виклику стандартних методів
/ / … створення його імені …
CosNaming:: Name_var nc = rootN-> to_name ("OtherContext.Context");
/ / … створення нового пустого контексту в
/ / Контексті rootN …
CosNaming::NamingContext_var ct = rootN->new_context ();
/ / … зіставлення імені і нового контексту з
/ / Перезаписом старого імені, якщо таке вже було
rootN->rebind_context (nc, ct);
/ / … і перетворення створеного контексту до
/ / Стилю INS
CosNaming::NamingContextExt_var firstCtx =
CosNaming::NamingContextExt::_narrow (ct);
/ / Створення імені, сопоставленного з об'єктом
CosNaming:: Name_var oc = rootN-> to_name ("NamedObject.Object Reference");
/ / … і одночасне створення контексту в
/ / Контексті firstCtx із зіставленням з новим
/ / Контекстом імені об'єкта, об'єктної посилання (у
/ / Режимі перезапису старого імені)
firstCtx-> rebind (oc, myPOA-> servant_to_reference (& servant));


Метод servant_to_reference () дозволяє вам отримати об'єктну посилання для вже існуючого або знову створюваного в неявному режимі -об'єкта.


Створювати ієрархію контекстів імен програмно, звичайно, не дуже зручно. На щастя, існують інструменти, які дозволяють зробити це в інтерактивному графічному режимі. Одним з таких інструментів є VisiBroker Console.


Тепер подивимося, що потрібно написати на стороні клієнта. На щастя, там все набагато простіше:






:: Object_var nsv = orb-> resolve_initial_references ("NameService");
CosNaming::NamingContextExt_var rootN =
CosNaming::NamingContextExt::_narrow (nsv.in());
if(::is_nil(rootN))
{
Cout <<"Не знайдено root контекст" <<endl;
/ / Обробка помилок пропущена
}
CosNaming:: Name_var nc = rootN-> to_name ("OtherContext.Context"
“/NamedObject.Object Reference”);
::Object_ptr o = rootN->resolve(nc);
MyInterface_ptr oRef = MyInterface::_narrow (o);

Залишилося відповісти на питання: який контекст повертає метод resolve_initial_references ()?


Оскільки загального стандартного єдиного Root-контексту, як уже говорилося, не існує, то кореневої контекст повинен бути заданий, наприклад, в якості аргументу командного рядка під час запуску серверного та клієнтського додатків. Існує два види завдання Root-контексту – «в стилі NS» і «в стилі INS».


У стилі NS запуск примірника Служби Імен може виглядати так:






start NameExtF [-SVCnameroot <root_name>] factory_name log_name, де:

<root_name> – ім'я контексту, який буде розглядатися як кореневої;


factory_name – ім'я створюваного при запуску NameExtF -об'єкта;


log_name – ім'я файлу, з якого при запуску зчитується попередній стан ієрархії імен, а при зупинці зберігається поточний стан.


Той же ключ –SVCnameroot – повинен використовуватися як параметр командного рядка під час запуску додатків, які використовують даний екземпляр служби імен.


У стилі INS і екземпляр служби імен, і параметри командного рядка задаються по-іншому. Попереджаємо вас: це реалізація для VisiBroker ще не затвердженої специфікації, тому, як кажуть, «можливі варіанти ». Приклад запуску екземпляра:






nameserv -J-Dvbroker.se.iiop_tp.scm.iiop_tp.listener.port=22000

Така команда приведе до запуску екземпляра служби імен, і ім'я створеного -об'єкта буде «NameService». Якщо ви хочете використовувати інше ім'я, вкажіть його після списку опцій.


Ключ-J каже, що наступний параметр просто передається як аргумент командного рядка під час запуску віртуальної машини Java. Так, це так – Inprise намагається все стандартні засоби писати на Java. Це, до речі, відноситься і до компілятора idl2cpp. Це забезпечує просту переносимість коштів на всі платформи, які підтримує VisiBroker.


У командному рядку програми, що використовує INS, потрібно вказати, до якого -об'єкту (тобто примірнику служби імен) ви хочете «приєднатися» і, відповідно, який отримати Root-контекст. Ось як може виглядати командний рядок запуску програми, що використовує запущений на тому ж самому комп'ютері за допомогою вищенаведеної командного рядка примірник Служби Імен:






Client-ORBInitRef NameService = iioploc: / / localhost: 22000/NameService

Зауважимо, що ніщо (крім здорового глузду) не заважає вам реєструвати в службі імен імена тимчасових об'єктів. Взагалі, сама по собі завдання, які -об'єкти повинні бути зроблені доступними, а які – ні, не дуже проста.


Використання Trader Service


Трейдер-Сервіс, загалом, набагато цікавіше Служби Імен, але й істотно складніше. У всіх статтях, книгах, описах і т.п. наводиться одна і та ж аналогія з «Жовтими Сторінками» телефонних довідників, але що робити – ця аналогія дійсно вірна.


У принципі, Трейдер можна розглядати як логічне розширення концепції Служби Імен: і там, і там з об'єктними посиланнями на потрібні -об'єкти зіставляється деяка інформація. Інша справа, що для Naming Service це просто рядок, а для Трейдера – сукупність довільної інформації, причому частина її може змінюватися динамічно, в процесі функціонування системи, а не визначена жорстко на стадії створення. Природним наслідком такого підходу є необхідність механізму формування запитів (що передбачає використання спеціального «мови» запитів), і управління їх виконанням. Як і Служби Імен, Трейдери можна об'єднувати в «федерації», при використанні яких одні Трейдери стають клієнтами інших; при цьому, як правило, клієнт розглядає федерацію трейдерів як один трейдер.


У даному розділі ми не будемо приводити фрагментів коду, а просто опишемо ключові концепції Трейдера.


Як і для Служби Імен, необхідно створити екземпляр Трейдера, який є -об'єктом, а потім приєднатися до нього тим чи іншим чином.


Ось основні поняття і концепції, на яких заснований Трейдер-Сервіс:



Один і той же провайдер сервісу може бути експортований неодноразово (зазвичай з різним набором властивостей). З іншого боку, один і той же набір властивостей може бути використаний для експорту різних провайдерів сервісу.

Читач, який захоче докладніше ознайомитися з усіма одинадцятьма інтерфейсами Трейдер-Сервісу, може знайти всю необхідну інформацію в специфікації OMG (документ 97-12-23.pdf). Ця специфікація містить 100 сторінок (порівняйте з 18 для Naming Service і 38 для Interoperable Naming Service).


Автоматичний запуск серверів додатків


Як вже говорилося, клієнту для встановлення зв'язку з серверним -об'єктом не потрібний ні сервант, ні працююче серверний додаток, яке здатне створювати серванти. Інша справа – виклик методів віддалених об'єктів.


Цілком очевидно, що універсальна технологія створення розподілених систем не може покладатися на «ручний» запуск серверів додатків. Зрозуміло, що розподіленою системою, що складається з декількох -додатків, буде вкрай важко керувати.


Для вирішення цієї проблеми передбачає спеціальний компонент, який дозволяє автоматично (за запитом клієнта) запускати потрібні сервери. Цей компонент називається «репозитарієм Реалізація». У VisiBroker, наприклад, цей Репозитарій називається Object Activation Daemon (OAD).


Як і майже всі компоненти , Репозитарій Реалізація сам є -об'єктом, і з ним необхідно встановити зв'язок тим чи іншим чином. Після створення такого об'єкту (звичайно це відбувається автоматично при запуску деякої стандартної програми) з'являється можливість («вручну», за допомогою командного рядка або GUI-інтерфейсу, або програмно) реєстрації сервера додатків. Примірник репозитарію Реалізація повинен бути запущений на тому ж комп'ютері, де буде виконуватися сервер додатків.


При використанні репозитаріїв реалізацій для persistent-серверних об'єктів при спробі віддаленого виклику за раніше отриманою об'єктної посиланням використовується не конкретну адресу об'єкта (ім'я хоста, порт і т.д.), а інформація про «записи» в Репозитарії. Ця інформація містить все необхідне для автоматичного запуску серверного додатку. Природно, при зміні запису про серверному додатку в Репозитарії Реалізацій, клієнт може звертатися до різних додатків на різних комп'ютерах.


Використання репозитаріїв реалізації дозволяє також визначити режим запуску серверного додатка – чи потрібно запускати один примірник для обслуговування всіх запитів, чи потрібно запускати окремий екземпляр для обслуговування кожного клієнта або навіть одного-єдиного запиту.


Стандарт не вимагає, щоб ці Репозитарії були реалізовані якимсь стандартним чином. Кожен виробник програмного забезпечення робить це по-своєму, тому, якщо ви створили серверний додаток з використанням коштів, допустимо, Inprise, то зареєструвати цю програму ви повинні в OAD від Inprise (і мати на комп'ютері його працюючий екземпляр). Внаслідок цього, не має великого сенсу говорити, наприм

Схожі статті:


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

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*