Опубликован: 18.03.2010 | Доступ: свободный | Студентов: 840 / 85 | Оценка: 4.48 / 4.33 | Длительность: 12:01:00
Лекция 2:

Технология CORBA

Структура Transaction

Структура Transaction содержит информацию об отдельно проведенной транзакции, затрагивающей текущий счет. Фактически, структура содержит одну строку из таблицы transactions. В IDL -файле эта структура описана следующим образом:

struct Transaction
{
TransactionId id;
Money amount;
Time date; 
AccountId source;
AccountId destination;
wstring comment; 
};
Классы работы с базой данных

Все классы работы с базой данных вынесены в отдельное пространство имен database. Эти классы реализуют набор интерфейсов, практически полностью повторяющий внешние

интерфейсы системы, что позволяет достаточно прозрачным для серверного приложения

образом менять способ хранения данных. Рассмотрим код работы с базой данных на примере метода database ::AccountImpl:: ProcessTransaction. Код работы с SQL- сервером выделен жирным.

ACCOUNT RESULT ProcessTransaction( AccountId dest, Money amount, String comment, Transaction * trans  )
if (!IsAccountValid(  conn ,dest))
	return AR_INVALID_ACCOUNT_ID;
if  ( Balance() - amount < 0 )
	return AR_NO_ENOUGH_MONEY;

TransactionId id = ( conn_->Execute() << "select transactions_id.nextval from dual")->Fields->
	GetItem("nextval")->Value;conn_->BeginTransaction();conn_->Execute() <<"update accounts set 
	balance=(select balance+(" << amount<< ")   
	from accounts where id=" << dest << ")  
	where id=" << dest;conn_->Execute() << "update accounts set balance=(select balance-(" << amount<< ") 
	from accounts where id=" << id_ << ")  
where id=" << id_;conn_->Execute()  << "insert into transactions(id,source_account_id, 
	dest_account_id, "<< "amount,  transaction_comment,  transaction_date)  
	values ("<< id << ", " << id_ << ", 
	" << dest << ", " << amount << ",'" << comment << "', 
	"<< time( NULL )  << ")";conn_->CommitTransaction();
if (trans)
	*trans = ReadTransaction( id );
return AR_OK;
}

Остальные классы пространства имен database взаимодействуют с базой данных аналогичным образом.

Получение сообщений от базы данных о новых транзакциях

В описании кода создания базы данных было уделено внимание передаче серверу сообщения о появлении новых записей в таблице transactions. Теперь рассмотрим код, принимающий эти сообщения. Ниже полностью приведен текст функции, работающей в отдельном потоке и получающей сообщения от сервера базы данных.

DWORD 	stdcall ServerProc(  LPVOID data  )
{
database::IOnDBChanged * consumer = reinterpret_cast<database::IOnDBChanged *>(data);
SOCKET sock = socket( AF_INET,   SOCK_STREAM,   IPPROTO_TCP  ); 
hostent * localHost = gethostbyname(   ""  );
char* localIP = inet_ntoa(  *(struct in addr *)*localHost->h_addr_list  );
sockaddr_in saServer; 
saServer.sin_family = AF_INET;
saServer.sin addr.s_addr = inet addr(  localIP  ); 
saServer.sin port = htons(  12345  );
int res = bind(  sock,   (  sockaddr *  )   &saServer,   sizeof(  saServer )   );
assert( res != SOCKET_ERROR );
res = listen(  sock,   SOMAXCONN );
assert( res != SOCKET_ERROR );
fd_set readfds; 
FD_ZERO(  &readfds  ); 
FD_SET(  sock,   &readfds  );

while   (   !endListenSocket && select(  0,   &readfds,  NULL,  NULL,  NULL )   != SOCKET_ERROR )
	{
	SOCKET incoming = accept(  sock,   0,   0  );
	static const int SIZE = sizeof(database::AccountId); 
	char buf[SIZE];
	while (( res = recv( incoming, buf, SIZE, 0)) > 0) 
		{
		database::AccountId id = *reinterpret_cast< database::AccountId * >(buf );
		consumer->OnDBChanged( id );
		}
	closesocket( incoming );
	FD_ZERO( &readfds  ); 
	FD_SET( sock, &readfds  );
	}
return 0;
}

Первые строки этой функции получают -адрес сервера банковской системы и создают слушающий сокет. Затем при поступлении соединения читаются 8 байт, формирующих номер счета участника транзакции, и, наконец, вызывается метод сервера банковской системы, который уже шлет сообщение об изменении счета клиентскому приложению.

Клиентская часть

Рабочее место оператора представляет собой standalone java -приложение. На рабочем месте оператора должна быть установлена Java и VisiBroker для поддержки событий с сервера. При запуске приложения, оно подключается к CORBA-серверу для получения банковского интерфейса (Рис. 2.9).

Окно входа в систему

Рис. 2.9. Окно входа в систему
byte[] bankId = "Bank".getBytes();
orb_ = org.omg.CORBA.ORB.init(args,  null);
remoteBanking = banking.BankHelper.bind(orb , "/banking poa", bankId);
try 
	{
	org.omg.CORBA.Object obj  = orb.resolve_initial_references("RootPOA"); 
	rootPOA = POAHelper.narrow(obj); 
	}   
catch   (InvalidName invalidName)   
	{ invalidName.printStackTrace();
	}

При попытке войти в систему, производится попытка авторизации пользователя через банковский интерфейс.

Окно регистрации нового пользователя

Рис. 2.10. Окно регистрации нового пользователя
try 
{
acc = clientApplet_.getRemoteBanking().OpenAccount(account,  new String(PINPasswordField.getPassword()));
}   
catch   (BankException el)   
{
JOptionPane.showMessageDialog(clientApplet , el.message, "Error", JOptionPane.ERROR_MESSAGE);
return;
}

В случае проблем с авторизацией на сервере произойдет Exception, который будет обработан на клиенте и будет показано соответствующее сообщение, описывающее причину отказа.

При регистрации нового клиента (Рис. 2.10) производится соответствующий вызов банковского интерфейса.

long accId = clientApplet.getRemoteBanking().CreateAccount( accountTextField.getText(), new String(PINPasswordField.getPassword()));

JOptionPane.showMessageDialog(clientApplet, "Write down and remember your unique account number : 
	" + accId, "Succeded", JOptionPane.INFORMATION_MESSAGE);

При успешной авторизации клиента отображается список транзакций совершенных данным клиентом (Рис. 2.11).

Основное окно клиентской программы

увеличить изображение
Рис. 2.11. Основное окно клиентской программы

Для обработки событий сервера и обновления списка транзакций используется PushViewModel

pv = new PushView(clientApplet.getOrb(), account.ChannelIOR())   
{
public void push(org.omg.CORBA.Any data)   throws Disconnected 
	{
	UpdateAccountTable();
	}
public void disconnect push consumer()   
	{
	System.out.println("View.disconnect push consumer");
	}
};

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

Обработка IDL-файла

IDL-файл в чистом виде не пригоден для компиляции ни компиляторами языка С++,ни компиляторами Java.Для создания файлов, обрабатываемых этими компиляторами, необходимы дополнительные инструменты, которые "переведут" IDL -описания интерфейсов на язык, понятный компилятору. Для C++ соответствующий инструмент называется midl, а для Java - idl2java.Запуск midl производится средой разработки Microsoft \text{\textregistered} Visual Studio™ 2005,а для генерации Java -файлов создан пакетный файл, который вызывает idl2java с корректно установленными путями.

Java Stored Procedures

В коде создания базы данных был упомянут интересный фрагмент, начинающийся со строки create or replace and compile java source named "Trigger" as.Данный фрагмент иллюстрирует очень мощную особенность СУБД Oracle,называемую хранимыми процедурами на языке Java (Java Stored Procedures).Эти процедуры исполняются виртуальной машиной Java,встроенной в сервер базы данных. Хранимые процедуры на Java и классы, их содержащие, должны отвечать следующим требованиям:

  1. не должно быть конструкторов;
  2. переменные и методы должны быть объявленными как static;
  3. необходимо использовать текущее соединение с базой данных (не требуется имя пользователя и пароль);
  4. необходимо объявить output -переменные как массивы.

Затем эти хранимые процедуры могут вызываться из триггеров, а так же их выполнение может быть инициировано приложениями, подключенными к базе данных.

Тестовый клиент

В процессе отладки системы был создан тестовый клиент на языке C++, который создает два счета и переводит в несколько приемов средства с одного из этих счетов на уведомления от сервера об изменении счета. Полный исходный код тестового клиента может быть найден в каталоге с исходными текстами системы. Вывод тестового клиента в процессе работы приведен на Рис. 2.12.

Окно тестового клиента

увеличить изображение
Рис. 2.12. Окно тестового клиента

Состояния базы данных до и после выполнения тестового клиента приведены на Рис. 2.13 и Рис. 2.14 соответственно

База данных до запуска тестового клиента

увеличить изображение
Рис. 2.13. База данных до запуска тестового клиента
База данных после запуска тестового клиента

увеличить изображение
Рис. 2.14. База данных после запуска тестового клиента
Антон Зубеков
Антон Зубеков

Здравствуйте, подскажите пожалуйста где можно достать материалы по курсу Кросс-платформенные и многозвенные технологии, о которых говориться, к примеру, в Лекции 2. Пример "Служба мгновенных сообщений"