Створення додатків із застосуванням COM +. Частина 1, Різне, Програмування, статті

Зміст



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


Навіщо потрібні служби компонентів


Розробники й користувачі COM-серверів часто стикаються з різними проблемами, що виникають на етапі експлуатації при одночасному обслуговуванні великого числа клієнтів. Зокрема, при створенні COM-серверів доступу до даних, які обслуговують декількох клієнтів, слід подбати про підтримку декількох з’єднань з базою даних і про роботу з декількома потоками. Однак при великому числі обслуговуються клієнтів подібні програми пред’являють серйозні вимоги до споживаним їм ресурсів, наприклад через необхідність підтримувати багато сполук з базою даних. Створення ж і знищення COM-об’єктів на вимогу клієнтських додатків (особливо об’єктів, що надають доступ до даних), тягне за собою витрати часу, що несприятливо позначається на продуктивності таких додатків. Тому нерідко розробники намагаються створити додатковий код для здійснення спільного доступу багатьох клієнтів до декількох екземплярах COM-об’єктів, що постійно знаходяться в оперативній пам’яті (іноді говорять про так званий пулі об’єктів), при цьому кількість даних об’єктів повинно бути по можливості мінімальним (зазвичай таке спільне використання об’єктів позначають терміном object pooling). При необхідності звернення до COM-об’єкту клієнтське додаток може скористатися одним з об’єктів, запозичивши його з пулу, а потім повернути назад, не ініціюючи ні його створення, ні знищення.


Ще одна проблема, що нерідко виникає в процесі практичної реалізації проектів, що містять COM-сервери, полягає в тому, що реально створювані додатки, на відміну від навчальних і книжкових прикладів, можуть мати досить складну архітектуру і, зокрема, містити кілька різних сервісів проміжного шару для вирішення різних завдань. Наприклад, деякі з них можуть відповідати за надання доступу до даних з декількох різних СУБД (особливо це актуально в компаніях, колись зазнали так званої островковой автоматизації), і при цьому може виникнути потреба в інструменті, реализующем комплексну функціональність, зокрема здійснення розподілених транзакцій, які зачіпають бази даних, які обслуговуються різними серверними СУБД (наприклад, Microsoft SQL Server і Oracle).


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


Таким чином, існує потреба в розширенні COM-технології за допомогою служби, що забезпечує створення COM-об’єктів для спільного використання багатьма клієнтами, авторизований доступ до цих об’єктів, а при необхідності також обробку транзакцій цими об’єктами. Розширена таким чином технологія COM стала іменуватися COM +, а сам сервіс, який реалізує це розширення і є складовою частиною Windows 2000, отримав назву Microsoft Component Services (служби компонентів).


Слід нагадати, що попередня версія реалізації цього сервісу входить до складу Windows NT4 Option Pack – вільно розповсюджуваний пакет оновлень для Windows NT 4.0 і називається Microsoft Transaction Server 2.0 (MTS).


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


Перш ніж приступити до створення додатків із застосуванням служб компонентів, поговоримо про основні принципи їх роботи.


Як працюють служби компонентів


Розглянемо типовий сценарій роботи програми, що використовує служби компонентів. Користувач запускає клієнтську програму, реалізоване у вигляді виконуваного файлу або Web-додатки. Клієнтський додаток намагається встановити з’єднання з об’єктом COM +. Якщо компонент COM +, що містить такий об’єкт, реалізований у вигляді внутріпроцессного сервера, цей об’єкт може виконуватися в адресному просторі додатка dllhost.exe або в адресному просторі клієнтського додатку. (Якщо мова йде про Windows NT і Microsoft Transaction Server, то компонент, що містить такий об’єкт, обов’язково повинен бути реалізований у внутріпроцессном сервері, а виконується він в адресному просторі додатка mtx.exe; об’єкт MTS також може виконуватися і в адресному просторі клієнтського додатку.) У загальному випадку в об’єкті COM + може бути реалізована практично будь-яка функціональність, наприклад такий об’єкт цілком може бути сервером доступу до даних.


Якщо запит на установку з’єднання коректний, то в адресному просторі того додатка, в якому повинен функціонувати об’єкт, створюється так званий контекст об’єкта (якщо при цьому додаток dllhost.exe не запущено, відбувається його запуск). Контекст об’єкта містить такі додаткові відомості, які не передбачені специфікацією COM і тому не містяться в COM-об’єктах, – це правила доступу до об’єкта і спосіб участі його в транзакціях. Контекст створюється для кожного клієнта, обслуговує саме його (на відміну від власне COM-об’єкта) і «за дорученням» клієнта взаємодіє з COM-об’єктом, який може бути і щойно створеним, і узятим з наявного пулу об’єктів.


Після створення контексту клієнтське додаток може посилати об’єкту COM + запити на виконання його методів. Ці методи можуть, наприклад, виконувати запити до СУБД або реалізовувати якісь інші дії, в тому числі звертатися до іншого об’єкту COM + (в останньому випадку ми можемо говорити про «батьківських» і «дочірніх» об’єктах).


Якщо при виконанні якого-небудь методу об’єкта COM + (батьківського або дочірнього) виникає виняток, об’єкт інформує про це служби компонентів, а ті, в свою чергу, інформують про це звернулася до даного об’єкта додаток (або відповідно інший об’єкт COM +), а при необхідності проводять і додаткову обробку виключення.


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


Після цього короткого вступу розглянемо детальніше особливості функціонування об’єктів COM +.


Організація пулів об’єктів і ресурсів


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


Навіщо потрібна організація пулів об’єктів? Нерідко буває, що серверні об’єкти при своєму створенні споживають чималий обсяг інших ресурсів, створюючи, зокрема, великі тимчасові файли або мережевий трафік і т.д. Виходячи з викладених вище міркувань, такі типи об’єктів повинні бути створені одноразово в заздалегідь певній кількості з метою подальшого їх використання клієнтськими додатками. Якщо в якийсь момент число клієнтів, яким потрібен такий серверний об’єкт, перевищить кількість наявних примірників даних об’єктів, то слід створити додаткові їх екземпляри. Знищення додаткових примірників об’єктів, які стали непотрібними, потрібно проводити відповідно до заздалегідь встановленим для них максимальним часом існування в неактивному стані.


Реалізація пулів ресурсів в COM + здійснюється за допомогою спеціальних об’єктів, які кешує ресурси для того, щоб організувати їх колективне використання декількома об’єктами COM +, об’єднаними в додаток. Ці об’єкти носять назви resource dispensers (dispenser означає роздавальний пристрій або розподільник; призначення званих цим словом об’єктів – кешування загальних даних, не схильних зміни за допомогою транзакцій) і resource managers (менеждера ресурсів; вони використовуються при управлінні транзакціями і дозволяють здійснити такі стандартні вимоги до них, як ізоляція і атомарность транзакцій).


При створенні додатків COM + досить часто застосовується організація пулу з’єднань з базами даних, зокрема пулу з’єднань з ODBC-і OLE DB-джерелами. При застосуванні такого пулу знижується мережевий трафік між службами компонентів і сервером баз даних за допомогою зниження частоти установки і розриву з’єднань з сервером. Організація пулів підтримується драйверами, що задовольняють специфікаціям ODBC 3.0 і ODBC 3.5 та деякими OLE DB-провайдерами, зокрема OLE DB Provider for Microsoft SQL Server.



Управління транзакціями


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


Для управління розподіленими транзакціями використовується спеціальний сервіс – Microsoft Distributed Transaction Coordinator (MS DTC), який може бути активізований з програми Component Services Explorer (Кошти адміністрування об’єктів COM +, доступного в розділі Administrative Tools панелі управління Windows 2000), або з додатку Service Control Manager панелі управління Windows 2000, або з програми Enterprise Manager, що входить в комплект поставки Microsoft SQL Server 7.0 або 2000 (якщо такий є на комп’ютері). MS DTC являє собою службу операційної системи, яка координує транзакції, які використовують різні менеджери ресурсів, і дозволяє реалізувати дії, що зачіпають різні бази даних (ці бази можуть бути зроблені різними виробниками і перебувати на різних комп’ютерах) в рамках єдиної транзакції.


Як в COM + реалізовано розподілені транзакції? Коли який-небудь об’єкт COM + запитує доступ до бази даних, то драйвер відповідної СУБД перевіряє в контексті цього об’єкта, чи йому транзакція, і, якщо потрібно, інформує про це DTC. Потім драйвер звертається до менеджера ресурсів, відповідальному за базу даних, із запитом про початок транзакції в ній. І тільки тепер компонент може почати маніпулювати даними за допомогою цього драйвера.


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


Коли об’єкт COM +, відповідальний за будь-яку частину такої транзакції, завершує свою роботу, він викликає або власний метод SetComplete, якщо виконувані ним операції завершилися успішно, або метод SetAbort, якщо стався відкат транзакції. Далі DTC звертається до обох менеджерам ресурсів із запитом на завершення або відкат обох транзакцій. Таким чином, зміни в обох базах даних будуть або разом збережені, або разом скасовані (рис. 1).

Рис. 1. Реалізація розподіленої транзакції за допомогою DTC


Якщо об’єкт COM + повинен запобігти завершення або відкат розподіленої транзакції, він може викликати власний метод DisableCommit. Метод EnableCommit дозволяє DTC завершити всі відкриті незбережені транзакції.


Як правило, подібного роду транзакції можливі за участю СУБД, що підтримують двофазне завершення транзакцій (two-phase commit). Відомості про те, чи підтримує обрана СУБД двофазне завершення транзакцій, повинні міститися в документації, що поставляється з цією СУБД.


Слід зазначити, що частини розподіленої транзакції зазвичай реалізуються в різних об’єктах COM +. Раніше ми вже відзначали, що одні об’єкти, звані батьківськими, можуть ініціювати створення інших об’єктів, які називаються дочірніми. Якщо такий дочірній об’єкт генерує виняток у процесі маніпуляції з базою даних, служби компонентів будуть проінформовані про необхідність відкату транзакції. В цьому випадку DTC ініціює відкат транзакції батьківського об’єкта і повідомляє про це клієнтське додаток. Тому для реалізації подібного управління транзакціями слід помістити код, який реалізує різні частини розподіленої транзакції, в різні об’єкти COM +, а потім створити для них батьківський об’єкт. При використанні такого механізму контролю транзакцій клієнтське додаток може не містити ні коду, пов’язаного із завершенням або з відкотом транзакцій, ні коду, відповідального за з’єднання з базою даних.



Питання безпеки


Служби компонентів дозволяють використовувати список користувачів і груп користувачів Windows 2000 як список користувачів своїх об’єктів. При цьому для кожного об’єкту можна встановити правила його експлуатації різними користувачами і групами користувачів. Крім цього Онлайнові служби компонентів підтримують також механізм ролей. Роль в службах компонентів – це сукупність користувачів і груп користувачів, які мають право звертатися до інтерфейсів об’єктів, включених у даний додаток COM +. При використанні ролей можна не включати код реалізації правил безпеки в об’єкти COM +.


Необхідно підкреслити, що ролі служб компонентів не слід інтерпретувати як аналоги ролей серверних СУБД – останні є не сукупність користувачів, а сукупність привілеїв.


Розглянувши можливості служб компонентів, перейдемо до самих об’єктів COM +, а саме до того, яким вимогам вони повинні задовольняти і як вони реєструються.


Особливості об’єктів COM +


Вимоги до об’єктів COM +


Об’єкти COM + є серверами автоматизації і, як і інші подібні сервери, реалізують інтерфейс IDispatch. Всі об’єкти COM + підтримують специфічний для них інтерфейс IObjectControl, що містить методи для активації та деактивації об’єкту COM + та управління ресурсами, у тому числі сполуками з базами даних.


Серверний об’єкт COM + повинен мати стандартну фабрику класів і бібліотеку типів (і та і інша автоматично створюються при використанні експерта Transactional Object wizard). Крім цього компонент повинен, як і всі внутріпроцессние сервери автоматизації, експортувати функцію DllRegisterServer і здійснювати автоматичну реєстрацію його CLSID (експерт Transactional Object wizard автоматично генерує відповідний код).


Якщо передбачається колективне використання серверного об’єкта, він повинен не зберігати всередині себе відомості про стан даних, пов’язаних з конкретним клієнтом (наприклад, результати запитів, номери поточної записи в наборі даних і т.д.), а негайно пересилати такі відомості клієнтського додатку. Об’єкти, що задовольняють цій вимозі, позначаються терміном «не зберігають стан» (stateless objects).


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


Особливості управління об’єктами COM +


Об’єкти COM + об’єднуються у додатки COM + – Applications (в MTS вони називалися, «пакетами» – packages), кожен з яких може містити один або кілька об’єктів. Управління об’єктами та додатками COM + здійснюється за допомогою програми Componet Services Explorer, яке доступне в розділі Administrative Tools панелі управління Windows 2000.


Кожен об’єкт, зареєстрований як об’єкт COM +, має властивість Transaction Support, що визначає правила участі об’єкта в транзакціях. Це властивість приймає п’ять можливих значень:


Disabled – для даного об’єкта не створюється контекст транзакції;


Not Supported – служби Component Services не запускають компонент всередині контексту транзакції;


Supported – служби Component Services запускають компонент всередині контексту транзакції, якщо така запитана, в іншому випадку – поза контекстом;


Required – служби Component Services поміщають об’єкт в контекст транзакції при виклику будь-якого з методів. Якщо для цього об’єкта транзакція недоступна, ініціюється нова;


Requires new – служби Component Services ініціює нову транзакцію при створенні об’єкта незалежно від того, які транзакції в цей момент виконуються.


Говорячи про COM +, потрібно відзначити механізм обробки подій, що виникають в таких об’єктах. На відміну від подій COM, де за повідомленням клієнтів стежить сам сервер, в COM + за подіями та повідомленням стежать служби компонентів. При цьому для генерації подій створюється окремий об’єкт-видавець, до якого проводиться звернення в момент настання події. Потім служби компонентів звертаються до всіх клієнтів, підписаним на цю подію (вони містять об’єкти-передплатники).


Об’єкти-видавці не повинні містити реалізації своїх інтерфейсів – вона міститься не в серверному об’єкті, а в клієнтському додатку (в передплатника на дану подію). Тому після опису інтерфейсів компонент компілюється і реєструється в службах компонентів. При настанні події в об’єкті COM + слід ініціювати створення об’єкта-видавця і викликати метод, відповідний даної події. В об’єкті-передплатника (це звичайний COM-об’єкт), як правило, реалізується інтерфейс об’єкта-видавця, а також методи цього інтерфейсу (в даному випадку реалізація методів), які відіграють роль обробників подій, що генеруються об’єктом-видавцем. Зазначимо, що і об’єкт-видавець, і об’єкт-передплатник повинні бути зареєстровані в одному і тому ж додатку COM +.


Розглянувши особливості управління об’єктами COM +, з’ясуємо, як створюються такі об’єкти. Як засіб розробки ми будемо використовувати Delphi 6 і почнемо ми з класів Delphi, за допомогою яких можна створити такі об’єкти.



Класи Delphi для створення об’єктів


В Delphi 6 Enterprise є два класи для створення додатків COM + – TMtsAutoObject і TMtsDataModule. Обидва класу призначені для створення серверів автоматизації, що реалізують інтерфейс IObjectControl (Строго кажучи, реалізація цього інтерфейсу обов’язкове тільки для об’єктів MTS, але не обов’язкова для об’єктів COM +, хоча і в останньому випадку вона рекомендується). На відміну від класу TMtsAutoObject, клас TMtsDataModule являє собою модуль даних, в який можна поміщати невізуальні компоненти. Він реалізує інтерфейс IAppServer, що дозволяє застосовувати в додатках COM + компоненти DataSnap.


Обидва ці класу реалізують ряд методів, характерних для об’єктів COM +.





























Метод

Опис
SetComplete Викликається після того, як об’єкт COM + успішно виконав свою роботу і більше не потребує даних, пов’язаних з обслуговується їм клієнтом. Після виклику цього методу об’єкт стає неактивним. Якщо об’єкт виконується в контексті транзакції, виклик методу SetComplete означає, що ця частина транзакції готова до завершення
SetAbort Викликається в тому випадку, коли виникає необхідність відкату транзакції, в якій бере участь даний об’єкт. Якщо транзакція була запущена автоматично службами Component Services спеціально для цього об’єкта, вона буде припинена, а об’єкт буде знищений. Якщо ж об’єкт був частиною «чужий» транзакції, вона не буде завершена. Зазвичай цей метод викликається при обробці виключень в блоці except пропозиції try..except
EnableCommit Викликається, якщо об’єкт COM + може завершити свою транзакцію, не позбавляючись від даних, пов’язаних з клієнтом. Метод не ініціює знищення об’єкта. Його виклик означає, що транзакцію за участю цього об’єкту можна завершити
DisableCommit Викликається у випадку, якщо об’єкт не може завершити поточну транзакцію до тих пір, поки не буде викликаний EnableCommit або SetComplete
IsInTransaction За допомогою цього методу можна визначити, чи виконується цей об’єкт в транзакції
IsCallerInRole Цей метод має вхідним параметром типу WideString. З його допомогою можна перевірити, чи відповідає клієнт ролі, ім’я якої вказано у вхідному параметрі
IsSecurityEnabled Даний метод дозволяє перевірити, чи захищений об’єкт службами безпеки COM +

Створення серверних об’єктів


Можливості, що надаються службами компонентів, набагато ширше, ніж ті, які ми проілюструємо прикладами. Однак, на наш погляд, не можна обійти увагою такі питання, як створення об’єктів для доступу до даних (оскільки на сьогоднішній день це найбільш поширений тип завдань), а також реалізацію розподілених транзакцій (подібне завдання нерідко зустрічається на підприємствах, які зазнали свого час островковой автоматизації, так як ці підприємства на сьогоднішній день потребують інтеграції різнорідних додатків, що використовують СУБД (від різних виробників). Саме ці завдання ми і розглянемо.


Ми почнемо зі створення, по-перше, найпростішого сервера доступу до даних, який дозволяє маніпулювати даними таблиці Products бази даних Northwind, що входить в комплект поставки Microsoft SQL Server, а по-друге, клієнтського додатку для його тестування. Потім ми створимо другий об’єкт COM + для маніпуляції даними в таблиці, що зберігає відомості про замовлені товари (її ми створимо у цій же базі даних). Далі ми створимо об’єкт, що виконує транзакцію, яка зачіпає обидві таблиці, та активізує обидва раніше створених об’єкта всередині своєї транзакції. І нарешті, ми перенесемо таблицю Products з бази даних Northwind в базу даних Oracle 8 і внесемо відповідні зміни в компоненти доступу до даних нашого першого об’єкта COM +, щоб розглянути, як розподілені транзакції управляються за допомогою Distributed Transaction Coordinator.


Клієнтські програми та об’єкти COM + можуть розташовуватися як на одному і тому ж комп’ютері, так і на різних комп’ютерах одного домену (в цьому випадку ми можемо використовувати доступ за допомогою DCOM). Комп’ютер, на якому розташовані об’єкти COM + (далі ми будемо називати його серверним комп’ютером), повинен мати доступ до баз даних, до яких вони будуть звертатися.


Для доступу до даних обох СУБД ми будемо використовувати ADO, а результати запитів в клієнтську програму будемо передавати у вигляді наборів даних ADO Recordset. Якщо приклади виконуються не в Windows 2000 (І, отже, використовується не Component Services, а MTS), потрібно впевнитися, що на клієнтському і серверному комп’ютерах встановлені бібліотеки MDAC (Microsoft Data Access Components) і служба DCOM і що на серверному комп’ютері встановлений MTS (нагадаємо, що він входить до складу Windows NT Option Pack, а останній доступний на Web-сервері корпорації Microsoft). Перед тестуванням компонентів слід також запустити Distributed Transaction Coordinator.


В нашому першому прикладі ми покажемо, як створити найпростіший об’єкт COM +, а потім створимо найпростіше клієнтське додаток для його тестування.


Створення об’єкта COM + для доступу до даних


Перший об’єкт COM +, який ми створимо, буде маніпулювати даними в таблиці Products бази даних Northwind з комплекту поставки Microsoft SQL Serve 7.0 або 2000. В ньому ми реалізуємо методи для зменшення значення поля UnitsInStock і збільшення значення поля UnitsOnOrder даної таблиці (ці операції проводяться, коли зі складу замовляють товар), а також для відправки результатів в клієнтську програму з метою контролю результатів цієї маніпуляції даними.


Наше перше додаток буде складатися з наступних частин, зображених на рис. 2.

Рис. 2. Найпростіше додаток COM +


Створення об’єкта COM + ми почнемо з нового проекту бібліотеки ActiveX, викликавши пункт меню File / New / Other і вибравши значок ActriveX Library зі сторінки ActiveX вікна репозитарія об’єктів. Збережемо проект під ім’ям STOCK. Далі на сторінці Multitier вікна репозитарія об’єктів виберемо значок Transactional Data Module і заповнимо діалогову панель відповідного експерта. Як і у випадку звичайного COM-об’єкта, нам слід ввести ім’я COM-класу (назвемо його Stock_Data) і вибрати модель потоків (зазвичай в об’єктах COM + застосовується модель Apartment). Крім того, слід вибрати значення властивості Transaction Support створюваного об’єкта (у даному експерта вона носить назву Transaction model). Зараз ми виберемо значення Requires a transaction, що дозволить надалі використовувати цей об’єкт в якості учасника транзакції, ініційованої іншим об’єктом. Після цього будуть згенеровані модуль даних (нащадок класу TMtsDataModule) і відповідне бібліотека типів.


Тепер помістимо в створений модуль даних компоненти TADOConnection і TADOCommand. Властивість Connection компонента ADOCommand1 встановимо рівним ADOConnection1, а властивість ConnectionString компонента ADOConnection1 встановимо рівним:



Provider=SQLOLEDB.1;Password=””;
Persist Security Info=True;User ID=sa;
Initial Catalog=Northwind;Data Source=MAINDESK


Слід мати на увазі, що ім’я сервера, ім’я користувача і пароль на вашому комп’ютері можуть бути іншими. Потрібно також встановити властивість LoginPrompt компонента ADOConnection1 рівним False, щоб уникнути появи діалогу аутентифікації користувача на серверному комп’ютері при спробі активації створюваного об’єкта.


Тепер відкриємо бібліотеку типів створеного об’єкта і створимо в ній три нових методи. Перший з них, Dec_UnitsInStock, буде зменшувати значення поля UnitsInStock одній із записів таблиці Products, другий, Inc_UnitsOnOrder, буде збільшувати значення поля UnitsOnOrder тієї ж записи. Обидва ці методу повинні мати два цілих вхідних параметра – ProductID, що дорівнює значенню первинного ключа, що ідентифікує запис, і OrdQuantity, що дорівнює кількості одиниць замовленого товару. Третій метод (назвемо його Get_ProductList) буде повертати набір даних (ADO Recordset) з результатом запиту до таблиці Products в клієнтське додаток. Щоб мати можливість використовувати такий тип даних, пошлемося на бібліотеку Microsoft ActiveX DataObjects Recordset 2.6 Library в бібліотеці типів об’єкта stock (це можна зробити, вибравши пункт контекстного меню Show All Type Libraries закладки Uses в редакторі бібліотеки типів і відзначити зазначену вище бібліотеку в списку, що з’явився). Для створення методу Get_ProductList визначимо властивість ProductList типу Recordset, доступне тільки для читання.


Результат редагування бібліотеки типів представлений на рис. 3.

Рис. 3. Бібліотека типів об’єкта Stock_Data


Описавши методи об’єкта COM +, натиснемо кнопку Refresh Implementation в редакторі бібліотек типів. Тепер нам слід реалізувати ці методи. Перший з них, як було сказано раніше, зменшує значення поля UnitsInStock. Можливі значення цього поля повинні бути більше або дорівнювати нулю (таке обмеження, присутнє в базі даних і відображає очевидне бізнес-правило: число одиниць товару на складі не повинно бути негативним). Отже, цей метод є потенційним джерелом винятку, пов’язаного з порушенням серверного обмеження. Тому ми врахуємо цей факт в коді і опрацюємо виняток згідно з правилами, прийнятим в COM + і розглянутим вище. Таким чином, реалізація даного методу має вигляд:



procedure TStock_Data.Dec_UnitsInStock(ProductID,
   OrdQuantity: Integer);
begin
   try
/ / Єднаймося з базою даних
   ADOConnection1.Open;
/ / Текст запиту до бази даних
   ADOCommand1.CommandText :=
   UPDATE Products SET UnitsInStock=UnitsInStock-
   +IntToStr(OrdQuantity)+ WHERE ProductID=
   +IntToStr(ProductID);
/ / Виконуємо запит
   ADOCommand1.Execute;
/ / Розриває з’єднання з базою даних
   ADOConnection1.Close;
/ / Інформуємо Component Services про успішне
/ / Виконанні запиту
   SetComplete;
except
   ADOConnection1.Close;
/ / Інформуємо Component Services про невдалу спробу
/ / Виконання запиту
   SetAbort;
/ / Передаємо виняток зухвалому додатком
   raise;
  end;
end;


Другий метод змінює значення поля UnitsOnOrder. Тут ми також обробимо можливе виключення, оскільки виключення можуть виникати не тільки через порушення серверних обмежень, але й з інших причин (Наприклад, через розрив з’єднання з базою даних). Реалізація цього методу має вигляд:



procedure TStock_Data.Inc_UnitsOnOrder(ProductID,
   OrdQuantity: Integer);
begin
  try
/ / Єднаймося з базою даних
  ADOConnection1.Open;
/ / Текст запиту до бази даних
     ADOCommand1.CommandText :=
     UPDATE Products SET UnitsOnOrder=UnitsOnOrder+
     +IntToStr(OrdQuantity)+ WHERE ProductID=
     +IntToStr(ProductID);
/ / Виконуємо запит
     ADOCommand1.Execute;
/ / Розриває з’єднання з базою даних
     ADOConnection1.Close;
/ / Інформуємо Component Services про успішне
/ / Виконанні запиту
     SetComplete;
except
/ / Розриває з’єднання з базою даних
     ADOConnection1.Close;
/ / Інформуємо Component Services про невдалу спробу
/ / Виконання запиту
     SetAbort;
/ / Передаємо виняток зухвалому додатком
     raise;
   end;
end;


Третій метод звертається із запитом до таблиці Products для отримання її вмісту у вигляді ADO Recordset. Його реалізація така:



function TStock_Data.Get_ProductList: Recordset;
  var QRY: string;
begin
  QRY := SELECT ProductID, ProductName, UnitPrice, +
        UnitsInStock, UnitsOnOrder from Products +
        WHERE Discontinued=0;
  try
/ / Створюємо набір даних
   Result := CoRecordset.Create;
   Result.CursorLocation := adUseClient;
/ / Відкриваємо його
  Result.Open(QRY,ADOConnection1.ConnectionString,
   adOpenStatic,adLockBatchOptimistic, adCmdText);
/ / Розриває з’єднання з базою даних
   ADOCOnnection1.Close;
/ / Інформуємо Component Services про успішне
/ / Виконанні запиту
 SetComplete;
 except
/ / Розриває з’єднання з базою даних
   ADOConnection1.Close;
/ / Інформуємо Component Services про невдалу спробу
/ / Виконання запиту
   SetAbort;
/ / Передаємо виняток зухвалому додатком
   raise;
  end;
end;


Для работосособності даного методу слід послатися в секції Uses на модулі ADODB, ADODb_TLB, ADOR_TLB (останній генерується при посиланні на бібліотеку типів Microsoft ActiveX DataObjects Recordset 2.6 Library).


Тепер нам слід скомпілювати і зберегти проект, а потім зареєструвати його. Якщо розробка компонента, що містить наш об’єкт, велася на серверному комп’ютері, потрібно вибрати пункт головного меню Delphi Run / Install COM + Objects (в цьому випадку необхідно ввести ім’я нової програми COM +, в який слід встановити цей об’єкт – нехай він називається COMPlus_Demo).


Якщо ж розробка об’єкта велася не на серверному комп’ютері, то створений компонент – файл STOCK.DLL – слід скопіювати в будь-який каталог серверного комп’ютера і зареєструвати його за допомогою Component Services Explorer. В цьому випадку потрібно створити новий додаток COM +, клацнувши правою клавішею миші на елементі Computer / COM + Applications в лівій частині вікна Component Services Explore і потім вибравши з контекстного меню цього елемента пункт New / Application. Назвемо наш додаток COMPlus_Demo. Далі в створене додаток, поки що нічого не містить, додамо створений компонент. Для цього розкриємо список папок створеного програми, з контекстного меню розділу Components виберемо пункт New / Component і в що з’явилися діалогових панелях відповімо на питання, що стосуються встановлюваного компонента. Можна також просто перетягнути ім’я файлу компонента COM + в Component Services Explorer.


Після цього можливо знайти і додаток, і сам компонент в Component Services Explorer (рис. 4).

Рис. 4. Компонент Stock_Data, зареєстрований в Component Services


Створивши найпростіший компонент COM + і зареєструвавши його в Component Services, ми можемо приступити до створення клієнта.


Тестування об’єкта COM + для доступу до даних


Клієнт Component Services буде являти собою звичайне Windows-додаток (в загальному випадку це може бути і Web-додаток, але ми тут не будемо його розглядати). Створимо новий проект, помістимо на його форму компоненти TRDSConnection і TADODataSet. Властивість ServerName компонента RDSConnection1 встановимо рівним програмного ідентифікатору (ProgID) створеного раніше об’єкта COM + (в даному випадку stock.Stock_Data), а властивість ComputerName має дорівнювати імені серверного комп’ютера. Як вже говорилося вище, для з’єднання з віддаленим компонентом в цій ситуації використовується DCOM. Ніяких властивостей компонента ADODataSet1 в процесі розробки встановлювати не потрібно – він просто отримає набір даних на етапі виконання. Однак нам слід продемонструвати отриманий набір даних користувачеві, тому помістимо на форму компоненти TDataSource, TDBGrid і TDBNavigator і пошлемося в них на компонент ADODataSet1. Нарешті, помістимо компонент TEdit для введення числа одиниць замовленого товару і дві кнопки, за допомогою яких ми будемо викликати методи об’єкту COM +.


Наступний крок – створення обробників події OnClick цих кнопок. Перший з них буде отримувати від об’єкта COM + набір даних і відображати їх:



procedure TForm1.Button1Click(Sender: TObject);
begin
  try
/ / Створюємо контекст об’єкта Stock_Data
    RDSConnection1.Connected := True;
/ / Отримуємо набір даних в об’єкта Stock_Data
    RS := RDSConnection1.GetRecordset(ProductList,);
    ADODataSet1.Recordset := RS;
/ / Показуємо його користувачеві
    ADODataSet1.Open;
/ / Тепер можна викликати інші методи цього об’єкта
    Button2.Enabled := True;
  except
/ / Об’єкт не може повернути дані
ShowMessage (Список товарів недоступний);
/ / Тоді ми не можемо викликати його методи
    Button2.Enabled := False;
  end;
/ / Звільняємо контекст об’єкта
  RDSConnection1.Connected := False;
end;


Обробник події OnClick інший кнопки емулює обробку замовлення, викликаючи два інших методу нашого об’єкта:



procedure TForm1.Button2Click(Sender: TObject);
var
  PID, Quantity : Integer;
begin
/ / Ідентифікуємо товар за значенням поля ProductID
  PID := ADODataSet1.FieldByName(ProductID).AsInteger;
/ / Визначаємо, скільки одиниць товару ми хочемо замовити
  Quantity := StrToInt(Edit1.Text);
  try
/ / Створюємо контекст об’єкта Stock_Data
   RDSConnection1.Connected := True;
/ / Віднімаємо значення Quantity із значення
/ / Поля UnitsOnOrder
   RDSConnection1.AppServer.Dec_UnitsInStock(PID, Quantity);
/ / Додаємо Quantity до значення поля UnitsOnOrder
   RDSConnection1.AppServer.Inc_UnitsOnOrder(PID, Quantity);
   Button1Click(self);
  except
/ / В об’єкті виникло виняток
Showmessage (Замовлення не прийнятий);
  end;
/ / Звільняємо контекст об’єкта
  RDSConnection1.Connected := False;
end;


Нам слід також описати змінну RS:



var
    Form1 : TForm1;
    RS : _Recordset;


Тепер ми можемо скомпілювати і зберегти клієнтську програму, а потім скопіювати його на клієнтський комп’ютер. Запустимо клієнтську програму і натиснемо першу кнопку. Ми повинні отримати набір даних, який буде відображений в компоненті TDBGrid (рис. 5). Якщо при цьому відкритий і Component Services Explorer, можна спостерігати анімацію значка компонента, до якого відбувається звернення. Як тільки закінчиться пересилання даних, анімація повинна припинитися, оскільки свідчить про те, що об’єкт знаходиться в активному стані.


Тепер можна вибрати одну із записів отриманого набору даних, ввести ціле число (наприклад, 1) в компонент Edit1 і натиснути другу кнопку. Після цього набір даних повинен оновитися, і в обраній записи значення поля UnitsInStock повинно зменшитися, а значення поля UnitsOnOrder – збільшитися на введену в компонент Edit1 величину. Однак якщо ми спробуємо ввести в компонент Edit1 число, що перевищує значення UnitsInStock, то об’єкт COM +, виконуючи запитаний метод з цим параметром, ініціює порушення обмеження на значення цього поля, що міститься в базі даних, і, отже, виникнення виключення в самому об’єкті COM +. Після цього всі маніпуляції з даними припиняться, а виключення буде передано зухвалому додатком, яким в даному випадку є наше клієнтську програму. У ньому-то ми і побачимо повідомлення про помилку: «Замовлення не прийнятий».


Зверніть увагу на те, що відомості про кількість завершених і скасованих транзакцій можна знайти в розділі Distributed Transaction Coordinator / Transaction Statistics програми Component Services Explorer (Рис. 6).


Таким чином, ви навчилися створювати найпростіші об’єкти COM +, реєструвати і тестувати їх. Наступним кроком буде реалізація транзакції, що складається з декількох частин і реалізованої в різних об’єктах. Цьому буде присвячена друга частина даній статті.

Частина 2


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


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

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

Ваш отзыв

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

*

*