Технология CORBA
Технология CORBA
Лабораторная работа: Технология CORBA Пример 1. Тестирование CORBA-соединения клиента с сервером Рассмотрим создание примитивной клиент/серверной ИС, состоящей из: · CORBA-сервера, приветствующего обратившегося к нему CORBA-клиента; · CORBA-клиента, способного подключаться к CORBA-серверу. Построение CORBA-сервера Для построения CORBA-сервера нужно запустить мастера CORBA Server командой File | New | Other | Multitier | CORBA Server (рис. 1). Рисунок 1 Когда мастер создания сервера запущен, он ожидает от программиста некоторой дополнительной информации (рис. 2): 1. Какого рода CORBA-сервер следует создать: консольное приложение (опция Console Application) или оконное (Window Application)? Не лишне напомнить, что сервер CORBA - это программа, производящая экземпляры объектов и уведомляющая об этом все заинтересованные программы-клиенты. Рисунок 2 2. Имена IDL-файлов с описанием интерфейсов объектов (кнопка Add) либо, если отметить кнопку Add New IDL File, мастер сам создаст пустой IDL-файл и добавит его в проект. После нажатия кнопки OK генерируется новый проект, и в окне редактора открывается пустой IDL-файл. Следующим действием разработчика будет описание интерфейса объекта калькулятора на языке IDL (рис. 5.3). Рисунок 3 Сохраним полученное описание в файле с именем User.idl. Теперь можно создать интерфейс пользователя, как показано на рис. 4. Рисунок 4 В элемент управления Memo1 будет заноситься строка приветствия подключившегося к CORBA-серверу клиента. Сохраним проект под именем CORBAServerProject. Для создания импортируемого сервером объекта выполним команду File | New | Other | Multitier | CORBA Object Implementation для запуска соответствующего мастера (рис. 5). Рисунок 5 Запущенный мастер собирает необходимую для генерации кода информацию (название файла описания объекта на IDL и имя реализуемого интерфейса) и отбражает на экране диалоговое окно (рис. 5.6). . Рисунок 6 В поле Interface Name следует выбрать из выпадающего списка имя интерфейса User::Welcome; это приведет к автоматическому заполнению имени класса объекта и модуля, которые будут сгенерированы мастером CORBA Object Implementation. Имя самого объекта WelcomeObject проставляется в поле Object Names. В самом низу диалоговой панели в левой ее стороне находится кнопка Show Updates. Со включенной кнопкой Show Updates программист получает возможность видеть все изменения в проекте, происходящие при генерации новых файлов и автоматической модификации уже имеющихся исходных текстов. После нажатия на кнопку Ok появляется окно (рис. 7), в котором слева отображается список всех произошедших во время работы мастера действий, тогда как в правой панели находятся исходные тексты, являющиеся результатом подобных действий. Рисунок 7Эта панель - полноценный редактор, в котором можно тут же внести изменения. Если то или иное действие мастера программиста не устраивает, он может просто отключить кнопку напротив его названия в левой панели. И действие будет отменено. Создавая калькулятор, нужно найти действие с именем WelcomeImpl::Hello (в левой панели), переключиться на него и внутрь пока еще пустого (в правой панели) метода Hello внести код приветствия. Заметим, что для успешной компиляции этого кода в модуль нужно добавить заголовочный файл формы #include "CORBAServerUnit.h", а ссылку extern TForm1 *Form1;.Осталось построить проект (рис. 8). Рисунок 8CORBAServerProject.cpp#include <vcl.h>#pragma hdrstop//---------------------------------------------------------------------------#include "WelcomeServer.h"#include <corba.h>USEFORM("CORBAServerUnit.cpp", Form1);//---------------------------------------------------------------------------WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int){try{Application->Initialize();// Initialize the ORB and BOACORBA::ORB_var orb = CORBA::ORB_init(__argc, __argv);CORBA::BOA_var boa = orb->BOA_init(__argc, __argv);WelcomeImpl welcome_WelcomeObject("WelcomeObject");boa->obj_is_ready(&welcome_WelcomeObject);Application->CreateForm(__classid(TForm1), &Form1);Application->Run();}catch (Exception &exception){Application->ShowException(&exception);}catch (...){try{throw Exception("");}catch (Exception &exception){Application->ShowException(&exception);}}return 0;}WelcomeServer.cpp #pragma hdrstop #include <corba.h> #include "WelcomeServer.h" #include "CORBAServerUnit.h" //--------------------------------------------------------------------------- #pragma package(smart_init) extern TForm1 *Form1; WelcomeImpl::WelcomeImpl(const char *object_name): _sk_User::_sk_Welcome(object_name) { } void WelcomeImpl::Hello() { Form1->Memo1->Lines->Add ("Hello, client!"); } Интересной особенностью CORBA-мастеров C++ Builder является их умение синхронизировать изменения в описании объектной модели с генерируемыми исходными текстами. Каждый раз, когда программист модифицирует IDL-файл, среда разработки исправляет заглушки (stubs) и скелеты (skeletons) приложения, а также переделывает объект. Построение CORBA-клиента Действия, необходимые для проектирования клиентского приложения, обращающегося к серверу, также не сложны. Для построения CORBA-клиента нужно запустить мастера CORBA Client командой File | New | Other | Multitier | CORBA Server (рис. 5.9).
Рисунок 9 В появившемся диалоговом окне (рис. 5.10) нужно выбрать тип приложения и ввести имя IDL-файла user.idl, описывающего объект, к которому будет обращаться CORBA-клиент (можно и не указывать этого имени, а просто добавить IDL-файл в проект). Рисунок 10 Далее нужно спроектировать несложный интерфейс пользователя, позволяющий соединяться с CORBA-сервером (рис. 11). Рисунок 11 #include <vcl.h> #pragma hdrstop #include "CORBAClientUnit.h" #include "user_c.hh" // !!! //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm2 *Form2; //--------------------------------------------------------------------------- __fastcall TForm2::TForm2(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------- void __fastcall TForm2::Button1Click(TObject *Sender) { User::Welcome_var H = User::Welcome::_bind("WelcomeObject"); H->Hello(); } В обработчике нажатия на кнопку «Подключение к CORBA-серверу» помещают исходный текст, производящий вызов метода Hello() удаленного объекта WelcomeObject интерфейса Welcome модуля User. Тестирование ИС Для тестирования ИС следует активизировать утилиту Smart Agent из меню Tools (это программа c:\Inprise\vbroker\bin\osagent.exe) (рис. 12). Рисунок 12 и последовательно (вне среды C++ Builder) запустить CORBA-сервер и CORBA-клиент Пример 2. Создание многоуровневой ИС Рассмотрим пример создания многоуровневой ИС, в которой клиент из банкомата может обратиться к серверу банка и выполнить нужные ему операции (рис. 15). Рисунок 15Для ускорения обработки данных серверы банков реализованы в разных каналах. Пример следует рассмотреть самостоятельно, руководствуясь комментариями к нижеприведенному коду программы. Xaction.idl enum EnumAction { balance, withdraw, deposit }; enum EnumStatus { OK, invalid, complete, incomplete }; struct xaction { long UserID; long PIN; long account; double amount; ::EnumAction action; double balance; ::EnumStatus status; }; interface Server { exception NoServer { string message; }; ::xaction HandleTransaction( inout ::xaction Transaction ); /* raises( ::Server::NoServer ); */ long Balance(); }; banking.idl #include "xaction.idl" interface BankServer { ::xaction HandleTransaction( inout ::xaction Transaction ); long BankID(); }; module Bank { interface Account { float balance(); }; interface AccountManager { ::Bank::Account open( in string name ); }; }; Рисунок 16. Проект и интерфейс банкомата Рисунок 17. Режим «Администрирование» ATMUnit/h //--------------------------------------------------------------------------- #ifndef atmunitH #define atmunitH //--------------------------------------------------------------------------- #include <Classes.hpp> #include <Controls.hpp> #include <StdCtrls.hpp> #include <Forms.hpp> #include <ExtCtrls.hpp> #include <ComCtrls.hpp> #include <Buttons.hpp> //--------------------------------------------------------------------------- class ATMObject { private: long _ID; String _serverName; public: ATMObject(){_serverName = "Wells Fargo"; _ID = 100;}; ATMObject(String name){_serverName = name; _ID = 100;}; String serverName(){return _serverName;} void serverName(String name){_serverName = name;} long ID(){return _ID;} void ID(long id){_ID = id;} }; class TFormATM : public TForm { __published: // IDE-managed Components TEdit *NameBox; TEdit *PINBox; TEdit *AmountBox; TLabel *Label1; TLabel *Label2; TLabel *Label3; TRadioGroup *Action; TMemo *Memo1; TRadioGroup *AccountType; TStatusBar *StatusBar1; TBitBtn *BitBtn1; TBitBtn *BitBtn2; TGroupBox *GroupBox1; TGroupBox *GroupBox2; TBitBtn *BitBtn3; TLabel *Label4; TLabel *Label5; TBevel *Bevel1; void __fastcall FormCreate(TObject/* */ *Sender); void __fastcall BitBtn1Click(TObject *Sender); void __fastcall BitBtn2Click(TObject *Sender); void __fastcall BitBtn3Click(TObject *Sender); private: // User declarations public: // User declarations __fastcall TFormATM(TComponent* Owner); ATMObject * ATM; long __fastcall TestConnection(); }; //--------------------------------------------------------------------------- extern PACKAGE TFormATM *FormATM; //--------------------------------------------------------------------------- #endif ATMUnit.cpp #include <vcl.h> #pragma hdrstop #include "atmunit.h" #include "servname.h" #include "xaction_c.hh" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" USE_STD_NS TFormATM *FormATM; //--------------------------------------------------------------------------- __fastcall TFormATM::TFormATM(TComponent* Owner) : TForm(Owner) { } char * const * argV; int argC; //--------------------------------------------------------------------------- // ///////////////////////////////////// // Mimic streaming to VCL Memo Window // ///////////////////////////////////// class catchit: public streambuf { TMemo * M; int ct; String S; char * cbuff; public: catchit(TMemo *Memo){M = Memo; ct = 1;}; int sync(); int overflow(int ch); }; int catchit::overflow(int ch) { S += (char)ch; return 0; } int catchit::sync() { // M->Lines->Strings[ct++] = S; M->Lines->Add(S); S = ""; return ct; } // //////////////////////////////////////////// // class _update // Instantiate this object to interface with the view // Usage: new _update(FormATM); // //////////////////////////////////////////// class _update { private: TFormATM * theForm; public: __fastcall _update(TFormATM* ATMForm) { theForm = ATMForm; } long AccountType() { return (long)theForm->AccountType->ItemIndex + 1; } EnumAction ActionType() { return (EnumAction)theForm->Action->ItemIndex; } long UserID() { if (theForm->NameBox->Text == "John") return 0; if (theForm->NameBox->Text == "Bill") return 1; if (theForm->NameBox->Text == "Jim") return 2; if (theForm->NameBox->Text == "Gene") return 3; if (theForm->NameBox->Text == "Wally") return 4; if (theForm->NameBox->Text == "Frank") return 5; return -1; // неизвестный пользователь } long PIN() { try { return (long)theForm->PINBox->Text.ToInt(); } catch (Exception &e) { return (long)0; } } double Amount() { return theForm->AmountBox->Text.ToDouble(); } void UpdateList() { theForm->Memo1->Lines->Clear(); theForm->Memo1->Lines->Add("John, PIN:123, Bank 1"); theForm->Memo1->Lines->Add("Bill, PIN:456, Bank 1"); theForm->Memo1->Lines->Add("Jim, PIN:789, Bank 1"); theForm->Memo1->Lines->Add("Gene, PIN:123, Bank 2"); theForm->Memo1->Lines->Add("Wally, PIN:456, Bank 2"); theForm->Memo1->Lines->Add("Frank, PIN:789, Bank 2"); } void UpdateMemo(String str) { theForm->Memo1->Lines->Add(str); } void UpdateStatus(String str) { theForm->StatusBar1->SimpleText = str; } void Clear() { theForm->Memo1->Clear(); } }; #define mrOK 1 long __fastcall TFormATM::TestConnection() { // проверка соединения try { CORBA::ORB_ptr orb = CORBA::ORB_init(); Server_ptr S = Server::_bind(ServerNameDlg->ServerNameEdit->Text.c_str()); return S->Balance(); } catch(CORBA::Exception &e) { return 0; } } //--------------------------------------------------------------------------- void __fastcall TFormATM::FormCreate(TObject *Sender) { ATM = new ATMObject(); } //--------------------------------------------------------------------------- void __fastcall TFormATM::BitBtn1Click(TObject *Sender) { // Администрирование if (ServerNameDlg->ShowModal() == mrOK) { ATM->serverName(ServerNameDlg->ServerNameEdit->Text); } } //--------------------------------------------------------------------------- void __fastcall TFormATM::BitBtn2Click(TObject *Sender) { // Список клиентов _update * U = new _update(FormATM); U->UpdateList(); delete U; } //--------------------------------------------------------------------------- void __fastcall TFormATM::BitBtn3Click(TObject *Sender) { // Выполнение операции catchit cbuf(Memo1); ostream CCout(&cbuf); // Visibroker имеет предопределенный Cout // Создание интерфейса просмотра ATM-объекта _update* Input = new _update(FormATM); // Создание объекта транзакции xaction_var X = new xaction; // "Заселение" объекта транзакции X->UserID = Input->UserID(); try { X->PIN = Input->PIN(); } catch (Exception &e) { X->PIN = 0; } X->amount = Input->Amount(); X->action = Input->ActionType(); X->account = Input->AccountType(); X->balance = 0.00; X->status = incomplete; try { // Старт ORB CORBA::ORB_ptr orb = CORBA::ORB_init(); Input->UpdateStatus("* ORB Инициализирован."); // Присоединение к ATM-серверу Server_ptr ATMServer = Server::_bind(ATM->serverName().c_str()); Input->UpdateStatus("Присоединение к ATM-серверу завершено."); Input->UpdateStatus("ATM-сервер открыт."); // Передача транзакции ATM-серверу ATMServer->HandleTransaction(X); if (X->status == complete) { Input->UpdateMemo("Баланс счёта: $" + CurrToStr(X->balance)); Input->UpdateMemo("Транзакция завершена."); } else if (X->status == incomplete) { Input->UpdateMemo("Транзакция не обработана."); Input->UpdateMemo("Баланс счёта: $" + CurrToStr(X->balance)); } else if (X->status == invalid) { Input->Clear(); Input->UpdateMemo("* ID клиента и PIN не найдены!"); } } catch(const CORBA::Exception& e) { CCout << e._name() << endl; Input->UpdateStatus("* ATM-сервер отключен!"); } } //--------------------------------------------------------------------------- Servername.h //---------------------------------------------------------------------------- #ifndef servnameH #define servnameH //---------------------------------------------------------------------------- #include <vcl\System.hpp> #include <vcl\Windows.hpp> #include <vcl\SysUtils.hpp> #include <vcl\Classes.hpp> #include <vcl\Graphics.hpp> #include <vcl\StdCtrls.hpp> #include <vcl\Forms.hpp> #include <vcl\Controls.hpp> #include <vcl\Buttons.hpp> #include <vcl\ExtCtrls.hpp> //---------------------------------------------------------------------------- class TServerNameDlg : public TForm { __published: TButton *OKBtn; TButton *CancelBtn; TBevel *Bevel1; TLabel *Label1; TLabel *ServerNameLabel; TEdit *ServerNameEdit; TLabel *Label2; TButton *ConnectButton; TLabel *Label3; TLabel *CountLabel; TLabel *ResultLabel; void __fastcall FormShow(TObject/* */ *Sender); void __fastcall ConnectButtonClick(TObject/* */ *Sender); void __fastcall OKBtnClick(TObject/* */ *Sender); private: public: virtual __fastcall TServerNameDlg(TComponent* AOwner); }; //---------------------------------------------------------------------------- extern PACKAGE TServerNameDlg *ServerNameDlg; //---------------------------------------------------------------------------- #endif Servername.cpp #include <vcl.h> #pragma hdrstop #include "servname.h" #include "atmunit.h" //--------------------------------------------------------------------- #pragma resource "*.dfm" TServerNameDlg *ServerNameDlg; //--------------------------------------------------------------------- __fastcall TServerNameDlg::TServerNameDlg(TComponent* AOwner) : TForm(AOwner) { } //--------------------------------------------------------------------- void __fastcall TServerNameDlg::FormShow(TObject/* */ *Sender) { ServerNameLabel->Caption = FormATM->ATM->serverName(); ServerNameEdit->Text = ServerNameLabel->Caption; ResultLabel->Caption = ""; } //--------------------------------------------------------------------------- void __fastcall TServerNameDlg::ConnectButtonClick(TObject/* */ *Sender) { CountLabel->Caption = String(FormATM->TestConnection()); if (CountLabel->Caption == "0") ResultLabel->Caption = "* Соединения нет!"; else ResultLabel->Caption = "Соединение установлено."; } //--------------------------------------------------------------------------- void __fastcall TServerNameDlg::OKBtnClick(TObject/* */ *Sender) { if (CountLabel->Caption != String("0")) { FormATM->ATM->serverName(ServerNameEdit->Text); } } //--------------------------------------------------------------------------- Рисунок 5.18. Проект и интерфейс ATM-сервера #ifndef atmserverunitH #define atmserverunitH //--------------------------------------------------------------------------- #include <Classes.hpp> #include <Controls.hpp> #include <StdCtrls.hpp> #include <Forms.hpp> #include "xaction_s.hh" #include "banking_s.hh" #include <Buttons.hpp> //--------------------------------------------------------------------------- class TForm2 : public TForm { __published: // IDE-managed Components TLabel *Transactions; TEdit *Count; TEdit *ServerNameEdit; TLabel *Label1; TBitBtn *BitBtn1; TGroupBox *GroupBox2; TGroupBox *GroupBox1; TBitBtn *BitBtn2; TMemo *Memo1; TComboBox *BankBox; void __fastcall FormClose(TObject *Sender, TCloseAction &Action); void __fastcall BitBtn1Click(TObject *Sender); void __fastcall BitBtn2Click(TObject *Sender); private: // User declarations public: // User declarations __fastcall TForm2(TComponent* Owner); void StartServer(); void DownServer(); CORBA::ORB_var orb; CORBA::BOA_var boa; CORBA::Object_ptr obj; String CurrentServerName; }; //--------------------------------------------------------------------------- extern PACKAGE TForm2 *Form2; //--------------------------------------------------------------------------- #endif ATMServerUnit.cpp #include <vcl.h> #pragma hdrstop #include "atmserverunit.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm2 *Form2; //--------------------------------------------------------------------------- __fastcall TForm2::TForm2(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------- char * const * argV; int argC; //--------------------------------------------------------------------------- // ///////////////////////////////////// // Implement CORBA object from skeleton class // ///////////////////////////////////// class ATMServerImpl : public _sk_Server { public: ATMServerImpl(const char *object_name); void UpCount(int i = 0){ if (i == 1) { Form2->Memo1->Lines->Add("ATM-сервер включен."); return; } Form2->Count->Text = String(count++); } virtual xaction HandleTransaction(xaction& Transaction) { UpCount(); Form2->Memo1->Lines->Add("Банк найден."); Transaction.status = invalid; for (int i = 0; i < UserCount; i++) { if(Transaction.UserID == CardHolders[i]->UserID) { if (Transaction.PIN == CardHolders[i]->PIN) { Transaction.status = OK; try { BankServer_var BankServer = BankServer::_bind((*Banks[CardHolders[i]->Bank]).c_str()); BankServer->HandleTransaction(Transaction); Form2->Memo1->Lines->Add("Транзакция с " + *Banks[CardHolders[i]->Bank]); } catch(CORBA::Exception &e){ Form2->Memo1->Lines->Add("* Сервер банка недоступен!"); return Transaction; } } } } // Transaction.status = complete; return Transaction; } virtual CORBA::Long Balance(){UpCount(); return CORBA::Long(count);} class NoServer: public CORBA::UserException { public: NoServer(){} static ATMServerImpl::NoServer* _narrow() throw (CORBA::SystemException); }; private: int count; struct _user{ long UserID; long Bank; long PIN; }; _user * CardHolders[10]; long BankOne; long BankTwo; int UserCount; String * Banks[10]; }; ATMServerImpl::ATMServerImpl(const char *object_name=NULL) : _sk_Server(object_name) { count = 0; UserCount = 0; UpCount(1); Banks[0] = new String("BankOne"); Banks[1] = new String("BankTwo"); TStrings *SL = new TStringList(); SL->Add(*Banks[0]); SL->Add(*Banks[1]); Form2->BankBox->Items->Assign(SL); Form2->BankBox->ItemIndex = 0; BankOne = 0; BankTwo = 1; CardHolders[0] = new _user; CardHolders[1] = new _user; CardHolders[2] = new _user; CardHolders[3] = new _user; CardHolders[4] = new _user; CardHolders[5] = new _user; // user 1 CardHolders[0]->UserID = 0; // "John"; CardHolders[0]->PIN = 123; CardHolders[0]->Bank = BankOne; UserCount++; CardHolders[1]->UserID = 1; // "Bill"; CardHolders[1]->PIN = 456; CardHolders[1]->Bank = BankOne; UserCount++; CardHolders[2]->UserID = 2; // "Jim"; CardHolders[2]->PIN = 789; CardHolders[2]->Bank = BankOne; UserCount++; CardHolders[3]->UserID = 3; // "John"; CardHolders[3]->PIN = 123; CardHolders[3]->Bank = BankTwo; UserCount++; CardHolders[4]->UserID = 4; // "Bill"; CardHolders[4]->PIN = 456; CardHolders[4]->Bank = BankTwo; UserCount++; CardHolders[5]->UserID = 5; // "Jim"; CardHolders[5]->PIN = 789; CardHolders[5]->Bank = BankTwo; UserCount++; } ATMServerImpl* ATMServer; void TForm2::StartServer() { try { // Инициализация ORB и BOA orb = CORBA::ORB_init(argC, argV); boa = orb->BOA_init(argC, argV); if (obj) { Form2->Memo1->Lines->Add("* ATM-сервер уже активен!"); ServerNameEdit->Text = CurrentServerName; } else { // Создание нового серверного объекта obj = new ATMServerImpl(ServerNameEdit->Text.c_str()); //"Wells Fargo"); CurrentServerName = ServerNameEdit->Text; // Экспорт созданного объекта boa->obj_is_ready(obj); // Ожидание приходящих запросов // boa->impl_is_ready(); } } catch(const CORBA::Exception& e) { ShowMessage("* Перехвачено CORBA-исключение!"); } } void TForm2::DownServer() { try { if (obj) { boa->deactivate_obj(obj); obj->_release(); obj = obj->_nil(); } Form2->Memo1->Lines->Add("* ATM-сервер отключен!"); } catch(CORBA::Exception &e){ ShowMessage("* Проблема при отключении ATM-сервера!"); } } //--------------------------------------------------------------------------- class ServerThread : public TThread { public: __fastcall ServerThread(bool CS):TThread(CS){}; void __fastcall Execute() { try { // Инициализвция ORB и BOA CORBA::ORB_var orb = CORBA::ORB_init(argC, argV); CORBA::BOA_var boa = orb->BOA_init(argC, argV); // Создание нового серверного объекта ATMServerImpl ATMServer("Wells Fargo"); // Экспорт созданного объекта boa->obj_is_ready(&ATMServer); // Ожидание приходящих запросов boa->impl_is_ready(); } catch(const CORBA::Exception& e) { ShowMessage("* Перехвачено CORBA-исключение!"); } } }; ServerThread * ST; //--------------------------------------------------------------------------- void __fastcall TForm2::FormClose(TObject *Sender, TCloseAction &Action) { // отключение сервера BitBtn1->Caption = "Включение AYM-сервера"; DownServer(); } //--------------------------------------------------------------------------- void __fastcall TForm2::BitBtn1Click(TObject *Sender) { // включение/отключение ATM-сервера static bool ServerStarted = false; if (!ServerStarted) { // включение сервера Form2->Height = 237; BitBtn1->Caption = "Отключение ATM-сервера"; // ST = new ServerThread(false); StartServer(); } else { // отключение сервера Form2->Height = 108; BitBtn1->Caption = "Включение ATM-сервера"; DownServer(); } ServerStarted = !ServerStarted; } //--------------------------------------------------------------------------- void __fastcall TForm2::BitBtn2Click(TObject *Sender) { // подключение к серверу выбранного в списке банка try { // попытка подключения к серверу выбранного в списке банка BankServer_ptr BankServer = BankServer::_bind(Form2->BankBox->Items->Strings[BankBox->ItemIndex].c_str()); // занесение ID банка в Memo long ID = BankServer->BankID(); Form2->Memo1->Lines->Add( AnsiString ("Банк ") + (ID == 800 ? AnsiString("BankTwo") : AnsiString("BankOne")) + AnsiString(" подключен.")); } catch(CORBA::Exception &e){ ShowMessage(e._name()); } } Рисунок 5.19. Проект и интерфейс BankServerOne #ifndef BankUnitOneH #define BankUnitOneH //--------------------------------------------------------------------------- #include <Classes.hpp> #include <Controls.hpp> #include <StdCtrls.hpp> #include <Forms.hpp> #include <Buttons.hpp> #include <ComCtrls.hpp> //--------------------------------------------------------------------------- class TBankOneForm : public TForm { __published: // IDE-managed Components TEdit *CountBox; TLabel *Label1; TMemo *Memo1; TBitBtn *BitBtn1; TStatusBar *StatusBar1; void __fastcall BitBtn1Click(TObject *Sender); private: // User declarations public: // User declarations __fastcall TBankOneForm(TComponent* Owner); }; //--------------------------------------------------------------------------- extern PACKAGE TBankOneForm *BankOneForm; //--------------------------------------------------------------------------- #endif BankUnitOne.cpp //--------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop #include "BankUnitOne.h" #include "banking_s.hh" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" AnsiString Accounts [] = {"Проверка", "Кредит"}; AnsiString Operations [] = {"Баланс", "Снять", "Внести"}; TBankOneForm *BankOneForm; //--------------------------------------------------------------------------- __fastcall TBankOneForm::TBankOneForm(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------- char * const * argV; int argC; //--------------------------------------------------------------------------- // /////////////////////////////////////////// // Implement CORBA object from skeleton class // /////////////////////////////////////////// class BankServerImpl : public _sk_BankServer { public: BankServerImpl(const char *object_name); void UpCount(int i = 0) { if (i == 1) { BankOneForm->StatusBar1->SimpleText = "Сервер включен"; return; } BankOneForm->CountBox->Text = String(++count); } virtual long BankID() { return BankNumber; } virtual xaction HandleTransaction(xaction& Transaction) { bool PostChange = false; double workingBalance = 0; UpCount(); Transaction.status = incomplete; BankOneForm->Memo1->Lines->Add("ID клиента: " + String(Transaction.UserID)); BankOneForm->Memo1->Lines->Add("Счет: " + Accounts[Transaction.account]); BankOneForm->Memo1->Lines->Add("Операция: " + Operations[Transaction.action]); for (int i = 0; i < UserCount; i++) { if (Transaction.UserID == Customers[i]->UserID) { if (Transaction.account == 1) workingBalance = Customers[i]->AccountChecking; else workingBalance = Customers[i]->AccountSavings; switch (Transaction.action) { case balance: Transaction.balance = workingBalance; Transaction.status = complete; break; case withdraw: Transaction.balance = workingBalance; workingBalance -= Transaction.amount; if (workingBalance < 0) { Transaction.status = incomplete; } else { Transaction.balance = workingBalance; Transaction.status = complete; PostChange = true; } break; case deposit: workingBalance += Transaction.amount; Transaction.balance = workingBalance; Transaction.status = complete; PostChange = true; break; } if (PostChange) { if (Transaction.account == 1) Customers[i]->AccountChecking = workingBalance; else Customers[i]->AccountSavings = workingBalance; } } } return Transaction; } private: long BankNumber; int count; int UserCount; struct _user{ long UserID; double AccountChecking; double AccountSavings; }; _user * Customers[10]; }; BankServerImpl::BankServerImpl(const char *object_name = NULL): _sk_BankServer(object_name) { BankNumber = 900; count = 0; UserCount = 0; Customers[0] = new _user; Customers[1] = new _user; Customers[2] = new _user; Customers[0]->UserID = 0; // "John" Customers[0]->AccountChecking = 2000.00; Customers[0]->AccountSavings = 90.00; UserCount++; Customers[1]->UserID = 1; // Bill; Customers[1]->AccountChecking = 100.00; Customers[1]->AccountSavings = 500.00; UserCount++; Customers[2]->UserID = 2; // Jim; Customers[2]->AccountChecking = 1000.00; Customers[2]->AccountSavings = 5000.00; UserCount++; } //--------------------------------------------------------------------------- class ServerThread : public TThread { public: __fastcall ServerThread(bool CS):TThread(CS){}; void __fastcall Execute() { try { // Инициализация ОRB и BOA CORBA::ORB_var orb = CORBA::ORB_init(argC, argV); CORBA::BOA_var boa = orb->BOA_init(argC, argV); // Создание нового серверного объекта BankServerImpl BankServer("BankOne"); // Экспорт сервероного объекта boa->obj_is_ready(&BankServer); BankOneForm->StatusBar1->SimpleText = "Сервер включен"; // Ожидание приходящих запросов boa->impl_is_ready(); } catch(const CORBA::Exception& e) { ShowMessage("* Перехвачено CORBA-исключение!"); } } }; ServerThread * ST; //--------------------------------------------------------------------------- void __fastcall TBankOneForm::BitBtn1Click(TObject *Sender) { static bool Switch = false; Switch = !Switch; BitBtn1->Caption = "Отключение сервера банка"; if (Switch) ST = new ServerThread(false); else Close(); }
|