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

Технология CORBA

Пример "Книжный магазин "BookStore""

Общее описание

Разработаем систему заказов для книжного магазина, позволяющую:

  • обновлять и корректировать информацию о книгах, хранящуюся в базе данных (добавление новых книг, изменение цен и т.д.);
  • выполнять заказы клиентов и информировать их о произошедших изменениях;
  • обновлять информацию о книгах при ее изменении в базе данных.
Создание таблиц в базе данных

Следующий код создает данную таблицу:

create table BookStore
(
id	int primary key,
name	varchar(255),
author	varchar(255),
publisher	varchar(255),
price	float
);
Интерфейс системы

Для связи СОRBA -объектов необходимо задать IDL -интерфейс, позволяющий выполнять запросы клиента и обеспечивать доступ к книгам и их модификацию.

struct Book  
{
long	id;
string	name;
string	author;
string	publisher;
float price;
}
typedef sequence <Book> BookList;
interface User  
{
BookList  getBookList ();
string	getAdmin	();   // ior
};

interface Admin  
{
long	updateBook	(in Book book );
};

Структура Book позволяет описывать и хранить информацию о книге. Интерфейс User имеет два метода:

  • BookList getBookList (), данный метод возвращает список имеющихся на сервере книг, их названия, цену и прочую информацию;
  • string getAdmin (), данный метод возвращает строковое представление ior объекта для получения доступа к интерфейсу Admin.

Интерфейс Admin имеет единственный метод updateBook позволяющий добавлять новые книги и редактировать информацию о них.

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

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

Для клиента, написанного на Java,используется ORB из стандартной поставки JDK.

idlj.exe -fall Server.idl

Опция -fall говорит приложению сгенерировать помимо оберток над интерфейсами, необходимыми для использования чужих IDL -интерфейсов, шаблоны для реализации сервантов.

Для сервера, написанного на C++,используется ORB из библиотеки ACE/TAO,соответственно, для генерации вспомогательных классов используется специальное приложение:

tao_idl.exe -GI Server.idl

Опция -GI позволяет сгенерировать дополнительные ServerI.h/.cpp файлы, в которых описан каркас реализации серванта, и остается лишь реализовать его методы. Полный список сгенерированных файлов при запуске указанной команды:

  • ServerC. h/.cpp - файлы, предоставляющие доступ к IDL -интерфейсам (аналогичные файлы используются в клиенте, реализованном на Java);
  • ServerS. h/. cpp - файлы, описывающие абстрактные классы необходимые для реализации сервантов;
  • ServerI.h/.cpp - каркас реализации серванта.
Получение доступа к CORBA-интерфейсу

Клиенты, посылающие запросы к серверу реализованы на языке Java.В качестве ORB взят стандартный ORB, входящий в Java SDK.

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

  1. Инициализация ORB и активизация POA -менеджера
    // create and initialize the ORB 
    ORB orb = ORB.init(args,  null);
    POA rootpoa =   (POA)orb.resolve_initial_references("RootPOA"); 
    rootpoa.the_POAManager().activate();
  2. Получение доступа к объекту сервиса имен
    // get the root naming context
    org.omg.CORBA.Object objRef = orb.resolve initial references("NameService");
    // Use NamingContextExt instead of NamingContext.  This is 
    // part of the Interoperable naming Service.
    NamingContextExt ncRef = NamingContextExtHelper.narrow(objRef);
  3. Получение доступа к интерфейсу пользователя с помощью сервиса имен
    String name	= "BookStore.User";
    corbaUser     = UserHelper.narrow(ncRef.resolve_str(name));
  4. Получение доступа к интерфейсу администратора с помощью значения ior
    String adminlor = corbaUser.getAdmin();
    org.omg.CORBA.Object adminObj  = orb.string_to_object(adminlor); 
    corbaAdmin = AdminHelper.narrow(adminObj);
Обратная связь. Сервис событий

При изменении данных книги, сервер должен оповестить клиентов. Для этого можно использовать сервис событий (сервис EventService,входящий с состав пакета ACE/TAO).Для запуска сервиса событий необходимо выполнить следующие действия.

  1. Получение доступа к объекту сервиса событий
    CORBA::Object var eventServiceObj = namingContext->resolve str("CosEventService"); 
    EventChannel_var eventChannel = EventChannel::_narrow(eventServiceObj.in());
  2. Активизация сервиса и получение объекта поставщика событий
    SupplierAdmin_var supplierAdmin = eventChannel->for_suppliers(); 
    // Get a ProxyPushConsumer from the SupplierAdmin. 
    ProxyPushConsumer_var consumer =supplierAdmin->obtain_push_consumer(); 
    
    // Connect to the ProxyPushConsumer as a PushSupplier 
    //   (passing a nil PushSupplier object reference to it because 
    // we don't care to be notified about disconnects).
    consumer->connect_push_supplier(  CosEventComm::PushSupplier::_nil());
  3. Для генерации события необходимо создать объект события и передать его поставщику событий:
    const CORBA::String var notificationMsg = CORBA::string_dup("BookStore.Notify"); 
    	  CORBA::Any any; any <<= notificationMsg; consumer->push(any);
Обработка событий

На стороне клиента необходимо зарегистрировать обработчик событий. Для этого достаточно реализовать вспомогательный класс (в данном проекте это класс EventNotify ), унаследованный от базового класса - обработчика событий CosEventComm.PushConsumerPOA и реализующий методы, необходимые для обработки поступающих сообщений. Для регистрации обработчика событий необходимо:

  1. Получить доступ к объекту сервиса событий
    // Find the EchoEventChannel.
    org.omg.CORBA.Object eventServiceObj = ncRef.resolve str("CosEventService"); 
    EventChannel echoEC =EventChannelHelper.narrow(eventServiceObj);
  2. Создать обработчик событий
    // Instantiate an EchoEventConsumer_i servant. 
    notifier = new BookStore.Server.EventNotify(orb,   this); 
    // Register it with the RootPOA.
    byte  []  oid = rootpoa.activate object(notifier); 
    org.omg.CORBA.Object consumer_obj  =rootpoa.id_to_reference(oid); 
    CosEventComm.PushConsumer consumer =
    CosEventComm.PushConsumerHelper.narrow(consumer_obj);
  3. Зарегистрировать обработчик событий
    // Get a ConsumerAdmin object from the EventChannel. 
    CosEventChannelAdmin.ConsumerAdmin consumerAdmin =echoEC.for_consumers(); 
    
    // Get a ProxyPushSupplier from the ConsumerAdmin. 
    CosEventChannelAdmin.ProxyPushSupplier supplier = consumerAdmin.obtain_push_supplier(); 
    
    // Connect to the ProxyPushSupplier,  passing our PushConsumer 
    // object reference to it.
    supplier.connect_push_consumer(consumer);
Связь с базой данных

Для работы с базой данных сервер BookStore использует ODBC (Open Database Connectivity) драйвер. Покажем работу сервера с базой данных на примере запроса получения списка книг.

  1. Инициализация драйвера и окружения ODBC
    SQLHENV henv;
    SQLAllocHandle(SQL_HANDLE_ENV,   NULL,   &henv); 
    // tell to use 3rd ODBC version
    SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3,
    SQL_IS_INTEGER); 
    SQLHDBC hdbc;
    SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);
  2. Соединение с базой данных
    SQLDriverConnect(hdbc, NULL, (SQLCHAR*)dsn, SQL_NTS,
    outStr, MAX_NUM, &outStrLen, SQL_DRIVER_COMPLETE);

    При соединении указывается DSN (Data Source Name) - имя источника данных, установленных на компьютере, либо специфичные для конкретного драйвера параметры соединения.

  3. Отправка запроса
    SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
    static SQLCHAR querySql[] = "select id,  name, author, publisher,  price from BookStore";
    SQLExecDirect(hstmt, querySql, SQL_NTS);
  4. Обработка результатов запроса
    SQLBindCol(hstmt, i + 1, SQL_C_SLONG, (SQLPOINTER)&uid, sizeof(uid)); 
    SQLBindCol(hstmt, i + 1, SQL_C_CHAR, (SQLPOINTER)name,  MAXLEN);
    SQLBindCol(hstmt, i + 1, SQL_C_CHAR,(SQLPOINTER)author, MAXLEN); 
    SQLBindCol(hstmt, i + 1, SQL_C_CHAR, (SQLPOINTER)publisher, MAXLEN); 
    SQLBindCol(hstmt, i + 1, SQL_C_DOUBLE, (SQLPOINTER)&price, sizeof(price)); 
    for   (;;)   
    	{
    	if   (SQLFetch(hstmt)   == SQL_NO_DATA)   
    		{ break;
    		}
    	// process book info
    	}
  5. Завершение обработки запроса
    SQLCloseCursor(hstmt);
Обратная связь: Oracle AQ
  1. Создадим пользователя с правами на управление AQ
    create user BookAdmin identified by "12345" default tablespace USERS temporary tablespace TEMP;
    grant CONNECT, RESOURCE, CREATE SESSION, aq_administrator_role TO bookadmin; 
    grant EXECUTE on SYS.DBMS_AQ to BookAdmin;
    exec DBMS_AQADM.GRANT_SYSTEM_PRIVILEGE(privilege =>	'ENQUEUE_ANY', grantee =>'BookAdmin', admin option => FALSE);
    
    exec DBMS_AQADM.GRANT_SYSTEM_PRIVILEGE(privilege =>	'DEQUEUE_ANY', grantee =>'BookAdmin', admin option => FALSE);
  2. Зайдем в Oracle под этим пользователем
    connect BookAdmin/12345;
  3. Создадим очередь событий
    create type EventType as object(type int,   text varchar2(2000));
    exec DBMS_AQADM.CREATE_QUEUE_TABLE(queue_table =>  'EventTable', queue payload type =>  'BookAdmin.EventType');
    exec DBMS_AQADM.CREATE_QUEUE(queue_name =>  'EventQueue',   queue_table => 'EventTable');
    exec DBMS_AQADM.START_QUEUE(queue_name =>  'EventQueue');
  4. Создадим триггер, помещающий событие в очередь при добавлении в таблицу
    create or replace trigger inserttrigger after insert on BookStore declare
    queue_options	DBMS_AQ.ENQUEUE_OPTIONS_T;
    message_properties   DBMS_AQ.MESSAGE_PROPERTIES_T;
    message id	RAW(16);
    my_message	BookAdmin.EventType;
    begin
    my_message	:= BookAdmin.EventType(1, 'insert');
    
    DBMS_AQ.ENQUEUE(
    queue_name =>  'BookAdmin.EventQueue', enqueue_options => queue_options, 
    	message_properties => message_properties, payload => my_message, msgid => message_id);
    end;
  5. Сгенерируем Java имплементацию для типа BookAdmin.EventType
    set ORA_HOME=C:\oracle\ora92\
    set CLASSPATH=%ORA_HOME%jdbc\lib\classes12.zip;%ORA_HOME%sqlj\lib\translator.zip ;%ORA_HOME%sqlj\lib\runtime.zip
    
    jpub -user=BookAdmin/12345 -sql=EventType -usertypes=oracle -methods=false
  6. Напишем код на Java,извлекающий события из очереди AQ
    String URL = "jdbc:oracle:thin:@server:1521:DB";
    String USER = "BookAdmin"; 
    String PASSWORD = "12345"; 
    String QUEUE_NAME = "EventQueue"; 
    
    // Connect to DB
    Class.forName("oracle.jdbc.driver.OracleDriver"); 
    Connection connection =DriverManager.getConnection(URL, USER, PASSWORD);
    connection.setAutoCommit(false); 
    
    // Connect to AQ
    Class.forName("oracle.AQ.AQOracleDriver");
    AQSession session = AQDriverManager.createAQSession(connection); 
    AQQueue queue = session.getQueue(USER,  QUEUE_NAME); 
    
    // Dequeue AQ message
    AQMessage message = queue.dequeue(new AQDequeueOption(), EVENTTYPE.getORADataFactory());
    
    EVENTTYPE m =(EVENTTYPE) message.getObjectPayload().getPayloadData();
Работа приложения

Для доступа к базе данных книжного магазина необходимо запустить клиентское приложение r_admin.bat (Рис. 2.15).

В центре окна отображается список книг. Получение списка книг осуществляется посредством использования метода getBookList объекта User, предоставляемого сервером.

Клиентское приложение в действии

увеличить изображение
Рис. 2.15. Клиентское приложение в действии

После ввода информации добавляемой книги, а так же при изменении уже существующих параметров книги (Рис. 2.16), вызывается метод updateBook объекта Admin, предоставляемого сервером.

Редактирование информации о книге

увеличить изображение
Рис. 2.16. Редактирование информации о книге

На стороне сервера для предоставления соответствующих IDL -интерфейсов необходимо запустить серверное приложение r_server.bat.После запуска необходимо дождаться сообщения о завершении инициализации данных: запуск ORB,регистрация сервантов в сервисе имен, связь с базой данных (Рис. 2.17).

Консоль запущенного сервера

увеличить изображение
Рис. 2.17. Консоль запущенного сервера
Антон Зубеков
Антон Зубеков

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