Створення простого компонента сервісу на C + +. Частина 1: Огляд API C + + для архітектури компонентів сервісу (SCA) (исходники), Різне, Програмування, статті

Створення і підключення простого компонента сервісу на C + +


Про проект Tuscany


Apache Tuscany – це проект, що проходить етап дозрівання у фонді Apache Software Foundation. Одне із завдань проекту – це розробка робочого циклу на C + +, втілює наступні специфікації архітектури компонентів сервісу (Service Component Architecture, SCA):



  1. SCA Assembly Model (Модель складання архітектури компонентів сервісу);
  2. SCA C + + Client and Implementation (Клієнт і реалізація SCA C + +).

В рамках цієї статті ми розробимо і розмістимо компонент сервісу на C + + для робочого циклу C + + Apache Tuscany C + +.


Введення


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


Ми створимо спочатку один простий компонент SCA, потім ще один такий компонент, і з’єднаємо їх один з одним.


Як середовище розробки ми скористаємося Microsoft Visual studio, але можна використовувати також компілятор командного рядка і текстовий редактор. Ви побачите, як задати параметри для проекту studio і процес розробки програми.


ПРИМІТКА: Tuscany SCA залежить від проектів Tuscany SDO і Apache Axis2 / C. Перед початком роботи бібліотеки SCA / SDO Tuscany libraries і бібліотеки Apache Axis повинні знаходитися в каталогах, зазначених у змінній PATH. Додаткову інформацію можна знайти в інструкції по завантаженню для проекту.


Робочий цикл Tuscany SCA C + + повинен бути забезпечений інформацією про те, де розміщені модулі і компоненти. Корінь розміщення ідентифікується змінної оточення TUSCANY_SCACPP_SYSTEM_ROOT. Зараз ми задамо цю зміну, щоб можна було запустити тестову програму з Visual Studio. Якщо ви користуєтеся командним рядком, то не потрібно задавати змінну до початку робочого циклу.


TUSCANY_SCACPP_SYSTEM_ROOT визначає шлях, по якому робочий цикл буде шукати розміщуються модулі та підсистеми, про які буде розказано далі. Кореневий каталог повинен мати два підкаталогу з іменами “Modules” і “subsystems”.


Скористайтеся панеллю керування, щоб задати таке значення: TUSCANY_SCACPP_SYSTEM_ROOT = c: mybasicsample.


В Control Panel (Панелі управління) відкрийте вікно System (Система), потім перейдіть на вкладку Advanced (Додатково) і натисніть кнопку Environment Variables (Змінні середовища). Натисніть кнопку New (Створити) і задайте для Variable name (Ім’я змінної) значення TUSCANY_SCACPP_SYSTEM_ROOT, а для Variable value (Значення змінної) значення c: mybasicsample. Потім натисніть кнопку OK, щоб створити змінну оточення.


Створіть каталог з ім’ям mybasicsample, а в ньому два вкладених каталогу з іменами modules і subsystems.


Тепер можна переходити до розміщення. Мабуть, потрібно написати програму, яку ми будемо розміщувати.


Коротке резюме по специфікації SCA (ви, звичайно, прочитали специфікацію?) Нагадає нам, що система SCA складається з двох або більше підсистем. Кожна підсистема містить список moduleComponents. Кожен moduleComponent в дійсності реалізується небудь модулем. У світі C + + існує набір файлів описів XML, які використовуються в процесі компіляції для генерації заступників і пакувальників сервісів і в процесі робочого циклу для пошуку пропонованих сервісів. Має сенс вивчити інформацію про ці файли до того, як ми приступимо до розробки. Файл, який описує підсистему, повинен мати ім’я sca.subsystem і розташовуватися в своєму підкаталозі каталогу subsystems кореневого каталогу. Файл sca.subsystem описує, які компоненти moduleComponents включені в підсистему. Компонент moduleComponent може розглядатися просто як частина підсистеми, moduleComponent має ім’я, а також вказує на модуль, який реалізує поведінку компонента moduleComponent:


Лістинг 1. moduleComponent




<subsystem xmlns=”http://www.osoa.org/xmlns/sca/0.9″ name=”MyServiceSubsystem”>
<moduleComponent name=”MyModuleComponent” module=”FloatConverter” />
</subsystem>

Лістинг 1 повідомляє робочого циклу архітектури компонентів сервісу SCA, що moduleComponent “MyModuleComponent” реалізується модулем з ім’ям “FloatConverter”, тому тепер ми повинні створити цей модуль.


Файл sca.subsystem – це чистий об’єкт робочого циклу, він не обслуговує жодного завдання в процесі компіляції. Інші файли (файли componentType і файли sca.module) описують модуль “FloatConverter”, щоб його можна було знайти під час робочого циклу. Ці файли допомагають також генератору коду створювати пакувальники та заступники для сервісів. Більш детально ми познайомимося з цими файлами в процесі розробки, який описаний нижче.


А поки давайте повернемося до початку. Ми хочемо розмістити клас C + + як сервіс і помістити цей сервіс в модуль з ім’ям “FloatConverter”. Наступні етапи покажуть, як це зробити.


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


ПРИМІТКА: До того, як ви приступите до процесу розробки, необхідно мати або завантажити код SCA / SDO і вбудувати його, або завантажити двійкову версію, щоб надалі можна було повідомити вашому проекту, де знайти робочий цикл SCA. Тепер поставимо дві змінних оточення TUSCANY_SCACPP і TUSCANY_SDOCPP, які вказують каталоги проектів SCA і SDO, в яких знаходяться каталоги bin, lib; в них можна включати каталоги.


Для початку створимо абстрактний базовий клас, що представляє сервіс, який ми хочемо розмістити. Це еквівалентно опису java-інтерфейсу. Створюваний нами заголовний файл I буде використовуватися клієнтським додатком для розуміння доступного інтерфейсу сервісу.


В заголовному файлі з ім’ям “Example.h” знаходиться клас:


Лістинг 2. Приклад класу




class Example
{
public:
// we will get a float from a string
virtual float toFloat(const char* input) = 0;
// we will convert a float to a string
virtual char* toString(float value) = 0;
};

Нам потрібно повідомити генератору коду, який тип компонента буде демонструвати це абстрактне поведінку, тому ми створюємо файл componentType. Файл componentType file пов’язує ім’я реалізує класу з абстрактним поведінкою відповідно до угоди про використовувані назвах. Файлу присвоюється ім’я по класу реалізації, причому в ім’я включається посилання на абстрактний клас, тому в нашому випадку файл буде названо “ExampleImpl.componentType”:


Лістинг 3. файл componentType




<?xml version=”1.0″ encoding=”ASCII”?>
<componentType xmlns=”http://www.osoa.org/xmlns/sca/0.9″
xmlns:xs=”http://www.w3.org/2001/XMLSchema”>
<service name=”ExampleService”>
<interface.cpp header=”Example.h”>
</interface.cpp>
</service>
</componentType>

Лістинг 3 повідомляє генератору коду, що компонент з ім’ям “ExampleService” буде демонструвати поведінку, яка описується в файлі заголовка “Example.h”. Він також повідомляє робочого циклу, що сервіс, реалізований під заголовком “ExampleImpl.h” – це ExampleService.


Отже, в Visual Studio ми створимо проект win32 dll і вставимо в нього файл заголовка, наведений вище. Ми назвали проект “TheExampleProject”, тому передбачається, що створена dll за замовчуванням отримає ім’я “TheExampleProject.dll”. Тепер створіть реалізацію сервісу, яка, природно, викликає файли ExampleImpl.cpp і ExampleImpl.h:


Лістинг 4. Реалізація сервісу




#include “Example.h”
class ExampleImpl : public Example
{
public:
ExampleImpl();
virtual ~ExampleImpl();
// Example interface
virtual float toFloat(const char* input);
virtual char* toString(float value);
};
#include “ExampleImpl.h”
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
ExampleImpl::ExampleImpl()
{
}

ExampleImpl::~ExampleImpl()
{
}
// Example interface
float ExampleImpl::toFloat(const char* input)
{
if (input != 0)
{
float f = (float)atof(input);
return f;
}
return (float)0;
}
char* ExampleImpl::toString(float value)
{
char * r = new char[100];
sprintf(r,”The float is : %5.5f”, value);
return r;
}


До цього моменту DLL буде скомпільована і скомпонована, тому можна написати тестову програму, щоб використовувати API Example і протестувати його. Пропустіть цей крок, оскільки це, насправді, стандартний матеріал.


Тепер додамо інші фрагменти мозаїки, які зв’яжуть модуль “floatConverter” з кодом, який ми написали.


Робітникові циклу SCA необхідно знати, де розміщений сервіс. Використовуйте робочий цикл для пошуку модуля moduleContext в коді клієнта і для виклику методу “locateService”. За замовчуванням робочий цикл може визначити модуль moduleContext двома способами:



  1. За змінної оточення TUSCANY_SCACPP_DEFAULT_MODULE = / , в нашому прикладі це буде: TUSCANY_SCACPP_DEFAULT_MODULE = MyServiceSubsystem / MyModuleComponent;
  2. Код клієнта може визначити модуль за умовчанням за допомогою класу TuscanyRuntimе. Саме цей спосіб ми використовуємо в нашому прикладі.

Тепер робочого циклу залишається тільки знайти сервіс в модулі та ім’я скомпонованою DLL. Це здійснюється читанням файлу “sca.module”, як показано в лістингу 5.


Лістинг 5. Читання файлу sca.module




<?xml version=”1.0″ encoding=”ASCII”?>
<module xmlns=”http://www.osoa.org/xmlns/sca/0.9″
xmlns:v=”http://www.osoa.org/xmlns/sca/values/0.9″
name=”FloatConverter”>
<component name=”ExampleService”>
<implementation.cpp dll=”TheExampleProject.dll” header=”ExampleImpl.h”>
</implementation.cpp>
<properties>
</properties>
<references>
<references>
</component>
</module>

Тепер ми знаємо, що модуль FloatConverter містить компонент, який називається “ExampleService”. ExampleService реалізований в бібліотеці TheExampleProject.dll, а його методи описані у файлі заголовка “ExampleImpl.h”.


Тепер ми повинні додати файли sca.module і sca.subsystem в наш проект, просто щоб стежити за ними.


У нашого робочого циклу SCA тепер є вся інформація, яка необхідна для знаходження сервісу і виклику методу. Однак ми не можемо написати клієнт, який безпосередньо викликає сервіс, інакше ми отримаємо залежність в процесі компіляції в нашій бібліотеці dll, тому нам для виклику необхідний заступник, а бібліотеці потрібен пакувальник для упаковки сервісу. Вони будуть згенеровані інструментом scagen. Інструмент scagen використовує файл заголовка, описаний у файлі sca.module, і створює необхідний код. Вам залишається тільки запустити інструмент, повідомити йому, де знаходиться файл і куди записати висновок. Припустимо, що файл sca.module і исходник нашого проекту знаходяться в каталозі c: mybasicsampleExample. У каталозі c: mybasicsample введіть> scagen-dir Example-output Example


ПРИМІТКА: Звичайно, для цього вам потрібно мати доступ до інструмента scagen, і ви повинні знати, що scagen – це java-додаток. Якщо ви завантажили двійковий варіант, то scagen вже знаходиться в каталозі “bin”, в іншому випадку вам потрібно створити цю утиліту. Для створення scagen вам потрібно тільки встановити комплект java JDK (1.4.2 або більш пізні версії) і apache ant. Перейдіть в каталог tools / scagen в проекті sca і введіть “Ant”. У каталозі bin буде створена утиліта scagen.


Чотири згенерованих файлу матимуть імена відповідно до угоди про використовувані назвах, як показано в лістингу 6.


Лістинг 6. Утиліта scagen




<headername>_<servicename>_Proxy.cpp/.h and
<headername>_servicename>_Wrapper.cpp/.h

Додайте ці нові файли в проект visual studio.


Тепер ваш проект залежить від sca, і не буде створено до тих пір, поки ви не повідомите йому, де знаходяться заголовки та бібліотеки sca. Додайте до шляху $ (TUSCANY_SCACPP) / include і $ (TUSCANY_SDO) / include для включення файлів заголовків (project, settings, C + +, preprocessor, additional include directories). Крім того, додайте файли tuscany_sdo.lib і tuscany_sca.lib в бібліотеки (link / input / Object / library modules). Додайте $ (TUSCANY_SCACPP) lib, $ (TUSCANY_SDOCPP) lib в якості додаткового шляху до бібліотек.


Тепер проект буде ще раз скомпільований, а ми можемо написати клієнт.


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


Тепер створіть файл cpp:


Лістинг 7. Файл cpp клієнта




#include “..MyServiceProjectExample.h”
#include “osoa/sca/sca.h”
#include <iostream>
#include <stdlib.h>
#include <tuscany/sca/core/TuscanyRuntime.h>
using namespace osoa::sca;
using namespace std;
int main(int argc, char* argv[])
{

if (argc != 2)
{
cout << “MyClient.exe: Would you cast me adrift without my float?” << endl;
return 0;
}

// Set the default moduleComponent
TuscanyRuntime runtime(“MyServiceSubsystem/MyModuleComponent”);
try {
runtime.start(); // bootstrap the Tuscany Runtime
// Get the current module context – (which is the default)
ModuleContext myContext = ModuleContext::getCurrent();
// Get an example service
Example *theService = (Example*) myContext.locateService(“ExampleService”);
if (theService == 0) {
cout << “MyClient.exe: Unable to find MyFloatService” << endl;
}
else {
try {
float result = theService->toFloat(argv[1]);
cout << “The float returned is ” << result << endl;
char *str = theService->toString(result + 1);
cout << “The string came back as ” << str << endl;
}
catch (char* x) {
cout << “MyClient.exe: exception caught: ” << x << endl;
}
}
}
catch (ServiceRuntimeException& ex) {
cout << “MyClient.exe: runtime exception caught: ” << ex << endl;
}
runtime.stop(); // stop the Tuscany Runtime
return 0;
}


Ось і готово ваше перше додаток SCA, що викликає один сервіс з клієнта. Щоб розгорнути цю програму, ви повинні помістити об’єкти робочого циклу в каталог розміщення у відповідності з наступним списком:


У каталог TUSCANY_SCACPP_SYSTEM_ROOT / modules / Examplе:



У каталог TUSCANY_SCACPP_SYSTEM_ROOT / subsystems / Example:



Тепер, коли в змінної path розміщені файли tuscany_sca.dll, tuscany_sdo.dll і axis2 dlls і задана змінна оточення TUSCANY_SCACPP_SYSTEM_ROOT, додаток зможе виконуватися.


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


Сервіс може викликати інший сервіс, і ці сервіси можуть підключатися один до одного за умови, що робочий цикл дозволяє використання сервісу тим же способом, як він дозволяє виклик клієнта. Ключове поняття – це componentContext. Ми бачили, що в робочому циклі є модуль moduleContext, який дозволяє йому знайти сервіс. У сервісі також є componentContext, який дозволяє робочого циклу знайти сервіс, від якого залежить поточний сервіс.


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


Спочатку потрібно створити другий сервіс. Вам не потрібно пояснювати, як це робити. Ми просто створимо простий сервіс, який повертає рядок:


Лістинг 8. Приклад простого сервісу




class StringThing
{
public:
// we will get a string
virtual char* getString() = 0;
};
#include “StringThing.h”
class StringThingImpl : public StringThing
{
public:
StringThingImpl();
virtual ~StringThingImpl();
// interface
virtual char* getString();
};
#include “StringThingImpl.h”
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
StringThingImpl::StringThingImpl()
{
}

StringThingImpl::~StringThingImpl()
{
}
// interface
char* StringThingImpl::getString()
{
char * r = new char[100];
sprintf(r,”The string from stringthing”);
return r;
}


Тепер, перед повторним використанням інструменту scagen, потрібно створити новий файл componentType для нового компонента і додати новий компонент в файл sca.module. На завершення нам також потрібно повідомити системі, що перший componentType буде пов’язаний з другим. Це робиться за допомогою зміни файлу ExampleImpl.componentType.


Ось новий файл componentType (StringThingImpl.componentType):


Лістинг 9. StringThingImpl.componentType




<?xml version=”1.0″ encoding=”ASCII”?>
<componentType xmlns=”http://www.osoa.org/xmlns/sca/0.9″
xmlns:xs=”http://www.w3.org/2001/XMLSchema”>
<service name=”StringService”>
<interface.cpp header=”StringThing.h”>
</interface.cpp>
</service>
</componentType>

А це файл sca.module із змінами:


Лістинг 10. Файл sca.module зі змінами




>
<?xml version=”1.0″ encoding=”ASCII”?>
<module xmlns=”http://www.osoa.org/xmlns/sca/0.9″
xmlns:v=”http://www.osoa.org/xmlns/sca/values/0.9″
name=”FloatConverter”>
<component name=”ExampleComponent”>
<implementation.cpp dll=”TheExampleProject.dll” header=”ExampleImpl.h”>
</implementation.cpp>
<properties>
</properties>
<references>
<stringService>StringThing/StringService</stringService>
<references>
</component>
<component name=”StringThing”>
<implementation.cpp dll=”TheExampleProject.dll” header=”StringThingImpl.h”>
</implementation.cpp>
<properties>
</properties>
<references>
<references>
</component>
</module>

Файл ExampleImpl.componentType із змінами:


Лістинг 11. Файл ExampleImpl.componentType зі змінами




<?xml version=”1.0″ encoding=”ASCII”?>
<componentType xmlns=”http://www.osoa.org/xmlns/sca/0.9″
xmlns:xs=”http://www.w3.org/2001/XMLSchema”>
<service name=”ExampleService”>
<interface.cpp header=”Example.h”>
</interface.cpp>
</service>
<reference name=”stringService”>
<interface.cpp header=”StringThing.h”>
</interface.cpp>
</reference>
</componentType>

Зверніть увагу на те, що ми використовували ім’я, що починається з малої літери “stringService” для посилання на сервіс з ім’ям, що починається з великої літери “StringService”. При повторному запуску scagen ви помітите, що були створені два додаткових файлу. Це заголовок замінника і файл cpp для посилання на “stringService” при виклику з ExampleImpl. Вам потрібно додати ці два нові файлу в проект.


І, нарешті, ось новий код сервісу Example, який дозволяє новий сервіс, який використовує компонент componentContext:


Лістинг 12. Приклад сервісу




char* ExampleImpl::toString(float value)
{
char * r = new char[100];
// now make a service call to stringthing…
try {
ComponentContext myContext = ComponentContext::getCurrent();
StringThing* stringService = (StringThing*)myContext.getService(“stringService”);
if (stringService == 0)
{
cout << “unable to find string thing service” << endl;
}
else
{
char* chars = stringService->getString();
if (chars != 0)
{
sprintf(r,”%s and the float is %5.5f”,chars,value);
delete chars;
return r;
}
}
}
catch (ServiceRuntimeException& e)
{
cout << “Errror from service: ” << e << endl;
// .. just carry on
}
sprintf(r,”The float is : %5.5f”, value);
return r;
}

Нагадуємо, що у нас є новий сервіс, тому нам потрібно розмістити нові файли робочого циклу:



І, звичайно, файли dll і модуля теж змінилися, тому їх теж необхідно скопіювати.


Висновок


Ось і готова наша перша скомпонована і працює підсистема SCA. Рисунок 1 допоможе запам’ятати шлях, який використовується для дозволу імені сервісу. Сподіваємося, що цей приклад з рішенням дав вам відчуття ефективності архітектури компонентів сервісу. В якості вправи можна додати до компонентів деякі властивості або спробувати упакувати StringThing в іншу dll.


У наступній статті ми розглянемо вхідні та вихідні Web-сервіси та ставлення до axis2.


Рисунок 1. Компонування сервісу
 


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


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

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

Ваш отзыв

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

*

*