- •Государственный комитет рф по высшему образованию
- •0. Введение.
- •0.1. Идея общей интеграции.
- •0.2. Взаимодействие на уровне процедур.
- •0.3. Распределенные объекты.
- •0.4. Почему corba.
- •1. Поддержка на различных платформах.
- •2. Устойчивость стандарта.
- •3. Сложность освоения.
- •4. Поддержка повторного использования кода.
- •1. Постановка задачи.
- •1.1. Классические объекты.
- •1.2. Распределенные объекты в терминах спецификации corba.
- •1.3. Требования, предъявляемые к orb-у.
- •2. СпецификацияCorba.
- •2.1. Объектная модель.
- •2.2. Обзор архитектурыCorba.
- •2.3. Пример Брокеров Объектных Запросов.
- •3. Структура системы.
- •3.1. Уточнение деталей реализации.
- •3.2. Структура ядра системы.
- •3.3. Структура библиотеки.
- •3.4.Структура подсистемы обработки запросов.
- •3.5. Входные и выходные данные.
- •4. Протокол обменаGiop.
- •4.1. Особенности и цели протокола.
- •4.2. Обзор протоколаGiop.
- •4.3. Синтаксис Общего Представления Данных -cdr.
- •4.4. Формат сообщений протокола giop.
- •4.5. Транспорт для протоколаGiop.
- •4.6. Реализация взаимодействия по протоколуGiop.
- •4.7. Поддержка протоколаGiop в рамках отображения дляObject Pascal.
- •5. Разработка отображения для языкаObject Pascal.
- •5.1. Множественное наследование.
- •5.2. Статические экземпляры классов.
- •Initialization
- •Initialization
- •6. Технология написания и отладки приложений, работающих с распределенными объектами.
- •6.1. Этапы разработки программы.
- •6.2. Технология написания сервера объекта.
- •6.3. Технология написания клиента объекта.
- •6.4. Отладочные возможности библиотеки.
- •7. Пример программы, работающей с распределенными объектами.
- •7.1. Последовательность действий при создании объекта.
- •7.2. Объект библиотека.
- •7.3. Сервер объекта.
- •7.3. Клиент объекта.
- •7.4. Окончательный результат.
- •8. Анализ конкурентоспособности программного продукта.
- •8.1. Введение.
- •8.2. Ситуация на рынке.
- •8.3. Программные продукты - конкуренты.
- •8.4. Основные понятия.
- •8.5. Параметры для оценки эффективности.
- •8.6. Расчет эффективности.
- •8.7. Цена.
- •8.8. Конкурентоспособность.
- •8.9. Выводы и прогнозы.
- •9. Вопросы эргономики и их решение для создания комфортных условий труда программистов.
- •9.1. Введение.
- •9.2. Рабочее место программиста.
- •9.3. Вредные факторы, присутствующие на рабочем месте и их классификация.
- •9.4. Вредные производственные воздействия.
- •9.5. Эргономические требования.
- •9.6. Эргономика окружающей среды.
- •9.7. Экологическая безопасность.
- •9.8. Выводы.
9.6. Эргономика окружающей среды.
Для производительности труда программиста важное значение имеет оборудование рабочего места мебелью, соответствующей эргономическим стандартам, подбор цветовой гаммы при отделке поверхности стен и др. Особое внимание следует уделять правильному освещению рабочего места. Правильно спроектированное и выполненное производственное освещение оказывает благоприятное психологическое воздействие, повышает безопасность труда. Производственное освещение должно удовлетворять следующим требованиям:
освещенность на рабочем месте должна соответствовать гигиеническим нормам - удовлетворительная степень освещенности может быть достигнута применением трех ламп накаливания, рассчитанных на напряжение 220 В и имеющих мощность в 40 Вт каждая, также в дневное время освещение может быть естественным;
равномерное распределение яркости - может быть достигнута, например за счет использования нескольких источников света, либо применением ламп дневного освещения;
отсутствие резких теней в рабочей зоне, что достигается правильным выбором места в пространстве для источника освещения;
отсутствие в поле зрения прямой и отраженной блестности, для чего следует избегать использования гладких, блестящих поверхностей в зоне видимости с рабочего места оператора;
величина освещенности должна быть постоянной во времени - это означает отсутствие мигания источников освещения;
оптимальная направленность светового потока - рекомендуемый угол падения света на рабочую поверхность 60 градусов к ее нормали;
выбор спектрального состава, то есть естественное освещение плюс искусственный источник со спектральной характеристикой, близкой к солнечной.
9.7. Экологическая безопасность.
Современное вычислительное устройство - компьютер является устройством, которое практически не оказывает никакого вредного воздействия на экологическое состояние внешней окружающей среды. Ввиду этого можно считать, что вычислительные машины, с которыми работает программист экологически безопасны.
9.8. Выводы.
В данной главе были рассмотрены следующие факторы, которые влияют на организацию рабочего места программиста:
производственные вредные факторы;
эргономические требования;
экологические внешние факторы.
Приведены допустимые различными стандартами максимальные значения тех или иных вредных факторов и даны рекомендации по устранению или минимизации ущерба здоровью человека, наносимого различными вредными воздействиями.
Заключение.
В результате работы над системой Брокер Объектных Запросов были решены следующие задачи:
Разработана технология взаимодействия объектов, находящихся в разных приложениях и выполняющихся возможно на разных компьютерах.
Разработана структура и осуществлена реализация программного комплекса, позволяющая осуществлять взаимодействие распределенных объектов прозрачным для программиста способом.
Разработаны дополнительные библиотеки, которые существенно облегчают использование системы при программировании на языках C++ иObject Pascal.Для языкаObject Pascal разработаны дополнительные методы программирования, расширяющие функциональные возможности языка.
Произведена оптимизация критических участков программы с целью увеличения производительности.
Общий объем исходных текстов составляющих компонентов системы составляют более 500 Кбайт. Ввиду большого объема полностью воспроизвести их здесь невозможно, но часть приведена в приложении В.
При работе над системой был получен опыт использования всевозможных программных ресурсов, предосталяемых операционной системой Windows NT. Итогом изучение большого количества различных технических документов и спецификаций, а также разнообразных самостоятельных опытов и исследований расширилось представление об объектно-ориентированном программировании.
Но при всех своих достоинствах данная программная система не рассматривается как окончательный продукт, а лишь как первая пробная версия. Имеется большое количество возможностей, на данном этапе нереализованных, но являющихся мощными дополнениями к системе. Реализация части из них запланирована в ближайшем будущем.
Ожидается, что данная реализация Брокера Объектных Запросов найдет применение при разработке сложных распределенных систем и займет достойное место среди имеющихся и планируемых к реализации технологиях взаимодействия распределенных объектов.
Приложение А. Подборка статей из периодической литературы.
А.1. Журнал PC Week RE N 40 `96 от 8.10.96
А.2. Журнал Computer Week N 40 `96 31.10.96-6.11.96
А.3. ЖурналComputer Week N 41 `96 7.11.96-13.11.96
А.4. Журнал PC Week RE N 48 `96 от 3.12.96
Приложение Б. Листинг методов WriteLong иPutLong.
Б.1. Листинг метода WriteLong.
TStreamable.WriteLong: begin
:00423284 55 push ebp
:00423285 8BEC mov ebp,esp
:00423287 83C4F8 add esp,FFFFFFF8
:0042328A 53 push ebx
:0042328B 8955F8 mov [ebp-08],edx
:0042328E 8945FC mov [ebp-04],eax
strmable.200: Align4;
:00423291 8B45FC mov eax,[ebp-04]
:00423294 E83FFFFFFF call TStreamable.Align4
strmable.201: Stream.Write(L, 4);
:00423299 8D55F8 lea edx,[ebp-08]
:0042329C B904000000 mov ecx,00000004
:004232A1 8B45FC mov eax,[ebp-04]
:004232A4 8B4004 mov eax,[eax+04]
:004232A7 8B18 mov ebx,[eax]
:004232A9 FF5304 call [ebx+04]
strmable.202: end;
:004232AC 5B pop ebx
:004232AD 59 pop ecx
:004232AE 59 pop ecx
:004232AF 5D pop ebp
:004232B0 C3 ret
Б.2. Листинг методаPutLong.
TStreamable.PutULong: push ebx
:004234FC 53 push ebx
strmable.372: push edx
:004234FD 52 push edx
strmable.373: push eax
:004234FE 50 push eax
strmable.374: call TStreamable.Align4
:004234FF E8D4FCFFFF call TStreamable.Align4
strmable.375: pop eax
:00423504 58 pop eax
strmable.376: push eax
:00423505 50 push eax
strmable.377: mov eax,[eax+TStreamable.FStream]
:00423506 8B4004 mov eax,[eax+04]
strmable.378: lea edx,[esp+4]
:00423509 8D542404 lea edx,[esp+04]
strmable.379: mov ecx,4
:0042350D B904000000 mov ecx,00000004
strmable.380: mov ebx,[eax]
:00423512 8B18 mov ebx,[eax]
strmable.381: call dword ptr [ebx+vtWrite]
:00423514 FF5304 call [ebx+04]
strmable.382: pop eax
:00423517 58 pop eax
strmable.383: pop edx
:00423518 5A pop edx
strmable.384: pop ebx
:00423519 5B pop ebx
strmable.389: end;
:0042351A C3 ret
Приложение В. Фрагменты исходных текстов
В.1. Модуль “baseio.h” - файл заголовков подсистемы обработки запросов.
#if !defined(_BASEIO_H_)
#define _BASEIO_H_
#include "common\thread.h"
#include "common\pipe.h"
class Owned;
class Owner {
protected:
void addObject(Owned *);
void removeObject(Owned *);
void deleteObject(ULong);
Owned ** list;
ULong ownedCount;
public:
Owner();
virtual ~Owner();
const Owned* operator[](ULong) const;
ULong count() { return ownedCount; };
Boolean valid(Owned *, ULong&);
friend class Owned;
};
class Owned {
Owner * objOwner;
public:
Owned(Owner *);
virtual ~Owned();
Owner * owner() { return objOwner; };
};
class Ownered : public Owner, public Owned {
public:
Ownered(Owner * anOwner) : Owned(anOwner) {};
};
typedef void (*OnReceive)(void * info, Octet * message, ULong size);
class IOException {
};
class Receiver : public Owned {
protected:
void * info;
public:
OnReceive onReceive;
Receiver(Owner * owner, void * anInfo)
: Owned(owner), info(anInfo) {};
void receive(Octet * message, ULong size)
{ if(onReceive != NULL) onReceive(info, message, size); };
};
class Sender : public Owned {
public:
Sender(Owner * owner) : Owned(owner) {};
virtual ULong send(Octet * message, ULong size) = 0;
};
extern Char * defaultPipeName;
extern Char * corePipeName;
class PipeReceiver : public Receiver {
Pipe * input;
Thread * inthread;
public:
PipeReceiver(Owner * owner, void * anInfo, OnReceive onReceiveFunc, String inpipe);
virtual ~PipeReceiver();
friend class PipeinThread;
};
class PipeinThread : public Thread {
PipeReceiver * receiver;
public:
PipeinThread(PipeReceiver * aReceiver)
: Thread(True), receiver(aReceiver) {};
virtual void execute(void);
};
class PipeSender : public Sender {
Pipe * output;
public:
PipeSender(Owner * owner, String outpipe);
virtual ~PipeSender();
virtual ULong send(Octet * message, ULong size);
};
typedef void (* PropertyIterator)(void * info, String prop, String val);
class Context : public Owner, public Owned {
class Pair : public Owned {
public:
Char * property;
Char * value;
Pair(Owner * anOwner, Char * prop, Char * val)
: Owned(anOwner), property(prop), value(val) {};
~Pair();
};
public:
Owner * pairs;
Context(Owner * owner);
virtual ~Context();
void add(Char * prop, Char * val);
void add(const Char * prop, const Char * val);
void del(Char * prop);
Boolean find(Char * prop, void * info, PropertyIterator propIter);
};
class Stream {
public:
Octet * data;
ULong size;
ULong pos;
Stream();
~Stream();
void align2();
void align4();
void align8();
void putData(void * aData, ULong dataSize);
void putOctet(Octet value);
void putUShort(UShort value);
void putULong(ULong value);
void putDouble(Double value);
void putString(String value);
void getData(void * aData, ULong dataSize);
Octet getOctet();
UShort getUShort();
ULong getULong();
Double getDouble();
void getString(String& value);
};
class OperationRequest : public Owned {
Context * context;
CORBA_Object object;
Identifier operation;
CORBA_NamedValue * result;
Flags flags;
Stream stream;
GIOP_ReplyStatusType status;
typedef enum { created, invoked, replied } RequestState;
RequestState state;
public:
OperationRequest(Owner *, CORBA_Object, Identifier, CORBA_NamedValue *, Flags, Context * = NULL);
virtual ~OperationRequest();
void send(Flags invoke_flags);
void reply(GIOP_ReplyStatusType status, Octet * data, ULong size);
friend CORBA_Status CORBACALL CORBA_Request_add_arg(CORBA_Request, CORBA_Identifier,
CORBA_TypeCode, CORBA_void *, CORBA_long, CORBA_Flags, CORBA_Environment *);
friend CORBA_Status CORBACALL CORBA_Request_get_response(CORBA_Request req,
CORBA_Flags response_flags, CORBA_Environment * env);
};
class RequestManager : public Ownered {
public:
RequestManager(Owner * anOwner) : Ownered(anOwner) {};
void reply(CORBA_Request req, GIOP_ReplyStatusType status, Octet * data, ULong size);
};
class ServerRequest : public Owned {
//Context * context;
CORBA_Object object;
Identifier operation;
Flags flags;
Stream stream;
public:
ServerRequest(Owner *, CORBA_Object, Identifier, Flags, Octet *, ULong);
virtual ~ServerRequest();
};
class RequestAnalyser : public Ownered {
public:
RequestAnalyser(Owner * anOwner) : Ownered(anOwner) {};
void request(CORBA_Object, Identifier, Flags, Octet *, ULong);
};
class Inbox : public Owner, public Owned {
public:
Inbox(Owner *);
void messageIn(Octet * message, ULong size);
};
class Outbox : public Owner, public Owned {
Sender * coreSender;
public:
Outbox(Owner *);
Sender * defaultSender() { return coreSender; };
void send(void *, ULong, Sender * = NULL);
};
class Daemon : public Owner {
public:
Inbox * inbox;
Outbox * outbox;
RequestManager * requestManager;
RequestAnalyser * requestAnalyser;
Ownered * contextManager;
Daemon();
virtual ~Daemon();
};
#endif
В.2. Модуль “baseio.cpp” - реализация подсистемы обработки запросов.
#include <dos.h>
#include <string.h>
#pragma hdrstop
#include "common\c\corba.h"
#include "common\c\easytyps.h"
#include "common\baseio.h"
/* Owner **************************************************/
const Owned* Owner::operator[](ULong index) const
{
return index < ownedCount ? list[index] : NULL;
};
void Owner::addObject(Owned * owned)
{
Owned ** newList = new Owned * [ownedCount + 1];
memmove(newList, list, ownedCount * sizeof(Owned *));
newList[ownedCount++] = owned;
delete[] list;
list = newList;
};
void Owner::removeObject(Owned * owned)
{
ULong i;
if(valid(owned, i)) deleteObject(i);
};
void Owner::deleteObject(ULong index)
{
Owned ** newList = new Owned * [ownedCount - 1];
memmove(newList, list, index * sizeof(Owned *));
memmove(newList + index, list + index + 1,
(ownedCount - index - 1) * sizeof(Owned *));
ownedCount--;
delete[] list;
list = newList;
};
Owner::Owner()
: list(NULL), ownedCount(0)
{};
Owner::~Owner()
{
while(ownedCount > 0) delete list[ownedCount - 1];
};
Boolean Owner::valid(Owned * owned, ULong& index)
{
for(ULong i = 0; i < ownedCount; i++)
if(list[i] == owned) { index = i; return True; };
return False;
};
/* Owned **************************************************/
Owned::Owned(Owner * anOwner)
{
objOwner = anOwner;
objOwner->addObject(this);
};
Owned::~Owned()
{
objOwner->removeObject(this);
};
/* Receiver * (empty) *************************************/
/* Sender * (empty) ***************************************/
/* PipeReceiver *******************************************/
PipeReceiver::PipeReceiver(Owner * owner, void * anInfo, OnReceive onReceiveFunc, String inpipe)
: Receiver(owner, anInfo)
{
onReceive = onReceiveFunc;
input = inpipe ? new Pipe(inpipe, True, Pipe::read) : NULL;
inthread = input ? new PipeinThread(this) : NULL;
};
PipeReceiver::~PipeReceiver()
{
delete inthread;
delete input;
};
#define MAGIC_LENGTH 4
#define SIZE_OFFSET 8
#define MESSAGE_LENGTH 12
void PipeinThread::execute(void)
{
Char message[MESSAGE_LENGTH];
ULong size;
Char * buffer;
while(True)
{
// to error recovery if such occure
while(1)
{ // read magic
receiver->input->readBuffer(message, MAGIC_LENGTH);
if(receiver->input->lastError == 0 &&
strncmp(message, GIOP_MAGIC, MAGIC_LENGTH )== 0) break;
sleep(1);
};
// read message header
receiver->input->readBuffer(message + MAGIC_LENGTH, SIZE_OFFSET);
size = *(CORBA_unsigned_long *)(message + SIZE_OFFSET);
buffer = new CORBA_char[size + MESSAGE_LENGTH];
memmove(buffer, message, MESSAGE_LENGTH);
// read the message
receiver->input->readBuffer(buffer + MESSAGE_LENGTH, size);
// process message received
receiver->receive(buffer, size + MESSAGE_LENGTH);
delete[] buffer;
};
};
/* PipeSender *********************************************/
PipeSender::PipeSender(Owner * owner, String outpipe)
: Sender(owner)
{
output = outpipe ? new Pipe(outpipe, False, Pipe::write) : NULL;
};
PipeSender::~PipeSender()
{
delete output;
};
ULong PipeSender::send(Octet * message, ULong size)
{
if(output != NULL) output->writeBuffer(message, size);
return output->lastError;
};
/* Context ************************************************/
Context::Pair::~Pair()
{
delete[] property;
delete[] value;
};
Context::Context(Owner * owner)
: Owned(owner)
{
pairs = new Owner;
};
Context::~Context()
{
delete pairs;
};
void Context::add(Char * prop, Char * val)
{
new Pair(pairs, prop, val);
};
void Context::add(const Char * prop, const Char * val)
{
add((Char *)strdup(prop), (Char *)strdup(val));
};
void Context::del(Char * prop)
{
ULong l = strlen(prop);
Boolean multi = False;
Pair * pair;
if(prop[l-1] == '*') { l--; multi = True; };
for(ULong i = pairs->count()-1; i >= 0; i--)
{
pair = dynamic_cast<Pair *>((Owned *)(*pairs)[i]);
if(multi)
{
if(strncmpi(prop, pair->property, l) <= 0) delete pair;
} else
{
if(stricmp(prop, pair->property) == 0)
{
delete pair;
break;
};
};
}
};
Boolean Context::find(Char * prop, void * info, PropertyIterator propIter)
{
ULong l = strlen(prop);
Boolean multi = False;
Boolean result = False;
Pair * pair;
if(prop[l-1] == '*') { l--; multi = True; };
for(ULong i = 0; i < pairs->count(); i++)
{
pair = dynamic_cast<Pair *>((Owned *)(*pairs)[i]);
if(multi)
{
if(strncmpi(prop, pair->property, l) <= 0)
{
result = True;
propIter(info, pair->property, pair->value);
}
} else
{
if(stricmp(prop, pair->property) == 0)
{
result = True;
propIter(info, pair->property, pair->value);
break;
};
};
}
return result;
};
/* Stream *************************************************/
Stream::Stream()
{
data = new Octet[size = 1024];
pos = 0;
};
Stream::~Stream()
{
delete[] data;
};
void Stream::align2()
{
if(size & 1) size++;
};
void Stream::align4()
{
if(size & 3) size += 4 - (size & 3);
};
void Stream::align8()
{
if(size & 7) size += 8 - (size & 7);
};
void Stream::putOctet(Octet value)
{
putData(&value, sizeof(value));
};
void Stream::putUShort(UShort value)
{
align2();
putData(&value, sizeof(value));
};
void Stream::putULong(ULong value)
{
align4();
putData(&value, sizeof(value));
};
void Stream::putDouble(Double value)
{
align8();
putData(&value, sizeof(value));
};
void Stream::putString(String value)
{
ULong ul = strlen(value) + 1;
putULong(ul);
putData(value, ul);
};
void Stream::putData(void * aData, ULong dataSize)
{
if(pos+dataSize > size)
{
while(pos+dataSize > size) size += 1024;
Octet * buffer = new Octet[size];
memmove(buffer, data, pos);
delete[] data;
data = buffer;
};
memmove(data+pos, aData, dataSize);
pos += dataSize;
};
void Stream::getData(void * aData, ULong dataSize)
{
if(pos + dataSize <= size)
{
memmove(aData, data + pos, dataSize);
pos += dataSize;
};
};
Octet Stream::getOctet()
{
return pos < size ? data[pos++] : 0;
};
UShort Stream::getUShort()
{
align2();
UShort us = 0;
if(pos+1 < size)
{
us = *(UShort *)(data + pos);
pos += 2;
};
return us;
};
ULong Stream::getULong()
{
align4();
ULong ul = 0;
if(pos+3 < size)
{
ul = *(ULong *)(data + pos);
pos += 4;
};
return ul;
};
Double Stream::getDouble()
{
align8();
Double d = 0;
if(pos+7 < size)
{
d = *(Double *)(data + pos);
pos += 8;
};
return d;
};
void Stream::getString(String& value)
{
ULong l = getULong();
value = strdup(data + pos);
pos += l;
};
/* OperationRequest ***************************************/
OperationRequest::OperationRequest(Owner * owner, CORBA_Object obj,
Identifier anOperation, CORBA_NamedValue * aResult, Flags aFlags, Context * ctx)
: Owned(owner), object(obj), operation(anOperation), result(aResult),
flags(aFlags), context(ctx), state(created)
{ };
OperationRequest::~OperationRequest()
{
};
void OperationRequest::send(Flags invoke_flags)
{
Stream strm;
strm.putData(GIOP_MAGIC, 4);
strm.putOctet(1);
strm.putOctet(0);
strm.putOctet(1);
strm.putOctet(Request);
strm.putULong(0); // length - while 0
strm.putULong(0); // list of service_context
strm.putULong(ULong(this)); // request_id
strm.putOctet((invoke_flags & CORBA_INV_NO_RESPONSE) != 0); // response_expected
strm.putULong(4); //// object_key
strm.putULong(ULong(object)); //
strm.putString(operation);
strm.putULong(0); // principal
strm.putData(stream.data, stream.pos); // request body
*(ULong *)(strm.data + 8) = strm.pos - 12;
dynamic_cast<Daemon *>(dynamic_cast<RequestManager *>(owner())->owner())->outbox->send(strm.data, strm.pos);
};
void OperationRequest::reply(GIOP_ReplyStatusType aStatus, Octet * data, ULong size)
{
state = replied;
status = aStatus;
CORBA_Environment env;
CORBA_TCKind kind = CORBA_TypeCode_kind(result->argument->_type, &env);
if(env._major != CORBA_NO_EXCEPTION) status = env._major;
else switch(kind)
{
case tk_octet: case tk_boolean: case tk_char:
*(Octet *)result->argument->_value = *(Octet *)data;
break;
case tk_short: case tk_ushort:
*(UShort *)result->argument->_value = *(UShort *)data;
break;
case tk_long: case tk_ulong: case tk_float: case tk_objref:
*(ULong *)result->argument->_value = *(ULong *)data;
break;
case tk_double:
*(Double *)result->argument->_value = *(Double *)data;
break;
};
};
/* RequestManager ****************************************/
void RequestManager::reply(CORBA_Request req, GIOP_ReplyStatusType status, Octet * data, ULong size)
{
ULong i;
if(valid((OperationRequest *)req, i)) dynamic_cast<OperationRequest *>(list[i])->reply(status, data, size);
};
/* ServerRequest ******************************************/
ServerRequest::ServerRequest(Owner * anOwner, CORBA_Object anObject,
Identifier anOperation, Flags anFlags, Octet * data, ULong size)
: Owned(anOwner), object(anObject), flags(anFlags)
{
operation = strdup(anOperation);
stream.putData(data, size);
};
ServerRequest::~ServerRequest()
{
delete[] operation;
};
/* Inbox **************************************************/
void messageIn(void * inbox, Octet * message, ULong size)
{
((Inbox *)inbox)->messageIn(message, size);
};
Inbox::Inbox(Owner * owner)
: Owned(owner)
{
new PipeReceiver(this, (void *)NULL, ::messageIn, (Char *)defaultPipeName);
};
void Inbox::messageIn(Octet * message, ULong size)
{
Stream strm;
if(!strncmp(message, GIOP_MAGIC, 4))
{
strm.putData(message, size);
strm.pos = 4;
strm.getOctet(); //major
strm.getOctet(); //minor
strm.getOctet(); //byte_order
switch(strm.getOctet()) // message_type
{
case Request:
case Reply:
{
ULong l = strm.getULong();
String s;
while(l) // service_context
{
strm.getULong();
ULong len = strm.getULong();
strm.pos += len;
l--;
};
CORBA_Request req = CORBA_Request(strm.getULong());
GIOP_ReplyStatusType status = strm.getULong();
dynamic_cast<Daemon *>(owner())->requestManager->
reply(req, status, strm.data + strm.pos, strm.size - strm.pos);
};
};
};
};
/* Outbox *************************************************/
Outbox::Outbox(Owner * anOwner)
: Owned(anOwner)
{
coreSender = new PipeSender(this, corePipeName);
};
void Outbox::send(void * message, ULong size, Sender * sender)
{
if(sender == NULL) sender = coreSender;
if(sender != NULL) sender->send((Octet *)message, size);
};
/* LibraryDaemon ******************************************/
Daemon::Daemon()
{
inbox = new Inbox(this);
outbox = new Outbox(this);
requestManager = new RequestManager(this);
contextManager = new Ownered(this);
};
Daemon::~Daemon()
{
delete requestManager;
delete outbox;
delete inbox;
};
В.3. Модуль “giop.pas” - абстрактные классы для работы по протоколуGIOP.
unit Giop;
interface
uses
Corba2, Iop;
type
MsgType = type Octet;
const
Request = MsgType(0);
Reply = MsgType(1);
CancelRequest = MsgType(2);
LocateRequest = MsgType(3);
LocateReply = MsgType(4);
CloseConnection = MsgType(5);
MessageError = MsgType(6);
type
Version = packed record
Major: Char;
Minor: Char;
end;
const
GiopMagic: array [0..3] of Char = 'GIOP';
type
{ general message header }
MessageHeader = packed record
Magic: array [0..3] of Char; // 'GIOP'
GIOPVersion: Version; // '1'.'0'
ByteOrder: Boolean; // True
MessageType: Octet;
MessageSize: ULong;
end;
type
{ request message header }
RequestHeader = packed record
ServiceContext: IOP.ServiceContextList;
RequestId: ULong;
ResponseExpected: Boolean;
ObjectKey: OctetSeq;
Operation: string;
RequestingPrincipial: CORBA2.Principal;
end;
type
{ reply message header }
ReplyStatusType = {type} ULong;
const
NO_EXCEPTION = ReplyStatusType(0);
USER_EXCEPTION = ReplyStatusType(1);
SYSTEM_EXCEPTION = ReplyStatusType(2);
LOCATION_FORWARD = ReplyStatusType(3);
type
ReplyHeader = packed record
ServiceContext: IOP.ServiceContextList;
RequestId: ULong;
ReplyStatus: ReplyStatusType;
end;
type
{ cancel request message header }
CancelRequestHeader = packed record
RequestId: ULong;
end;
type
{ locate request message header }
LocateRequestHeader = packed record
RequestId: ULong;
ObjectKey: OctetSeq;
end;
type
{ locate reply message header }
LocateStatusType = type ULong;
const
UNKNOWN_OBJECT = LocateStatusType(0);
OBJECT_HERE = LocateStatusType(0);
OBJECT_FORWARD = LocateStatusType(0);
type
LocateReplyHeader = packed record
RequestId: ULong;
LocateStatus: LocateStatusType;
end;
implementation
end.
В.4. Модуль“giopimp.pas” - реализация поддержки протоколаGIOP.
unit GiopImp;
interface
uses
SysUtils, Classes, Windows,
Corba2, {CorbaImp, }Iop, Giop, Strmable;
type
{ Header common class }
TBody = class(TStreamable)
protected
procedure Write; override;
procedure Read; override;
public
constructor Create;
end;
THeader = class(TStreamable)
protected
FBody: TBody;
public
constructor Create;
constructor CreateFromStream(Stream: TStream);
destructor Destroy; override;
function MsgType: MsgType; virtual; abstract;
property Body: TBody read FBody write FBody;
end;
{ MessageHeader wrapper }
TMessageHeader = class(TStreamable)
private
FHeader: THeader;
FMsgType: MsgType;
procedure SetHeader(AHeader: THeader);
protected
procedure Write; override;
procedure Read; override;
public
constructor Create;
destructor Destroy; override;
property Header: THeader read FHeader write SetHeader;
property MsgType: MsgType read FMsgType;
end;
{ RequestHeader wrapper }
TRequestHeader = class(THeader)
private
FId: ULong;
FResponseExpected: Boolean;
FObjectKey: Pointer; // wrong
FOperation: string;
protected
procedure Write; override;
procedure Read; override;
public
constructor CreateWithData(const AnOperation: string; AResponseExpected: Boolean);
function MsgType: MsgType; override;
property Id: ULong read FId write FId;
property ResponseExpected: Boolean read FResponseExpected write FResponseExpected;
property ObjectKey: Pointer read FObjectKey write FObjectKey; //wrong
property Operation: string read FOperation write FOperation;
end;
{ ReplyHeader wrapper }
TReplyHeader = class(THeader)
private
FId: ULong;
FReplyStatus: ReplyStatusType;
protected
procedure Write; override;
procedure Read; override;
public
function MsgType: MsgType; override;
property Id: ULong read FId write FId;
property ReplyStatus: ReplyStatusType read FReplyStatus write FReplyStatus;
end;
{ RequestHeader wrapper }
TCancelRequestHeader = class(THeader)
private
FId: ULong;
protected
procedure Write; override;
procedure Read; override;
public
function MsgType: MsgType; override;
property Id: ULong read FId write FId;
end;
implementation
constructor TBody.Create;
begin
Stream := TMemoryStream.Create;
end;
procedure TBody.Write;
begin
end;
procedure TBody.Read;
begin
end;
constructor THeader.Create;
begin
inherited Create;
FBody := TBody.Create;
end;
constructor THeader.CreateFromStream(Stream: TStream);
begin
inherited Create;
FBody := TBody.Create;
ReadFromStream(Stream);
FBody.Stream.CopyFrom(Stream, Stream.Size - Stream.Position);
FBody.Stream.Position := 0;
end;
destructor THeader.Destroy;
begin
FBody.Free;
end;
constructor TMessageHeader.Create;
begin
inherited Create;
FMsgType := MessageError;
end;
destructor TMessageHeader.Destroy;
begin
FHeader.Free;
inherited Destroy;
end;
procedure TMessageHeader.SetHeader(AHeader: THeader);
begin
FHeader := AHeader;
if FHeader = nil then FMsgType := MessageError
else FMsgType := Header.MsgType;
end;
procedure TMessageHeader.Write;
var
S: TStream;
begin
Stream.Write(GiopMagic, 4);
PutChar('1').PutChar('0').PutBoolean(True).PutOctet(MsgType);
if Header = nil then PutULong(0) else
begin
S := TMemoryStream.Create;
try
Header.WriteToStream(S);
Header.Body.Stream.Position := 0; // ???
S.CopyFrom(Header.Body.Stream, Header.Body.Stream.Size);
S.Position := 0;
PutStream(S);
finally
S.Free;
end;
end;
end;
procedure TMessageHeader.Read;
var
S: array [0..3] of Char;
Version: Giop.Version;
ByteOrder: Boolean;
MessageSize: ULong;
begin
Header.Free;
Stream.Read(S, 4);
if(StrLComp(S, GiopMagic, 4) <> 0) then BadStreamFormat;
GetChar(Version.Major).GetChar(Version.Minor).GetBoolean(ByteOrder).
GetOctet(Octet(FMsgType)).GetULong(MessageSize);
case MsgType of
Request : FHeader := TRequestHeader.CreateFromStream(Stream);
Reply : FHeader := TReplyHeader.CreateFromStream(Stream);
CancelRequest : FHeader := TCancelRequestHeader.CreateFromStream(Stream);
LocateRequest : BadStreamFormat;
LocateReply : BadStreamFormat;
CloseConnection : FHeader := nil;
MessageError : FHeader := nil;
end;
end;
constructor TRequestHeader.CreateWithData(const AnOperation: string; AResponseExpected: Boolean);
begin
inherited Create;
FOperation := AnOperation;
FResponseExpected := AResponseExpected;
end;
function TRequestHeader.MsgType: MsgType;
begin
Result := Giop.Request;
end;
procedure TRequestHeader.Write;
begin
PutULong(0).PutULong(Id).PutBoolean(ResponseExpected).
PutULong(ULong(ObjectKey)).PutString(Operation).PutULong(0);
end;
procedure TRequestHeader.Read;
var
CtxLen: ULong;
ObjectKeyAsULong: ULong;
PrnLen: ULong;
begin
GetULong(CtxLen);
if CtxLen <> 0 then BadStreamFormat; // Context
GetULong(FId).GetBoolean(FResponseExpected).GetULong(ObjectKeyAsULong).
GetString(FOperation).GetULong(PrnLen);
ObjectKey := Pointer(ObjectKeyAsULong); // wrong
if PrnLen <> 0 then BadStreamFormat; // Principal
end;
function TReplyHeader.MsgType: MsgType;
begin
Result := Giop.Reply;
end;
procedure TReplyHeader.Write;
begin
PutULong(0).PutULong(Id).PutULong(ReplyStatus);
end;
procedure TReplyHeader.Read;
var
CtxLen: ULong;
begin
GetULong(CtxLen);
if CtxLen <> 0 then BadStreamFormat; // Context
GetULong(FId).GetULong(FReplyStatus);
end;
function TCancelRequestHeader.MsgType: MsgType;
begin
Result := Giop.CancelRequest;
end;
procedure TCancelRequestHeader.Write;
begin
PutULong(Id);
end;
procedure TCancelRequestHeader.Read;
begin
GetULong(FId);
end;
end.
Приложение Г. Графические листы
Г.1. Лист 1. Структура ядра системы.
Г.2. Лист 2. Структура библиотеки.
Г.3. Лист 3. Структура подсистемы обработки запросов.
Г.4. Лист 4. Схемы алгоритмов кодирования сообщения, запроса, ответа.
Г.5. Лист 5. Схема алгоритма кодирования значения произвольного типа.
Г.6. Лист 6. Этапы создания приложений с распределенными объектами.
Г.7. Лист 7. Пример: Библиотека. Разработка сервера объекта.
Г.8. Лист 8. Пример: Библиотека. Разработка клиента объекта.
Г.9. Лист 9. Исследование конкурентоспособности программного продукта.
Приложение Д. Использованная литература
Thomas J. Mowbray, Ron Zahavi, The Essential CORBA: System Integration Using Distributed Objects, (Wiley, 1995)
Robert Orfali, Dan Harkey, Jery Edwards, The Essential Distributed Objects/Survival Guide, (Wiley, 1996).
CORBA: Common Object Request Broker Architecture and Specification.
AP-526. Application Note. Optimizations For Intel’s 32-Bit Processors, Intel, October 1995, Order No 242816-001.
Журнал Монитор-Аспект 2.94 стр. 80-84.
Журнал Мир ПК 10.96 стр. 10-20.
Журнал PC Magazine/RE 12.96 стр. 25-49.
1Соответственно в данном разделе тип объекта называется классом. Если упоминается термин объект, то имеется ввиду конкретный представитель, экземпляр класса.
2С целью упрощения изложения не рассматриваются некоторые частные случаи, такие как статические функции - члены класса, виртуальные функции и др.
3В скобках приводится название класса C++, который выполняет соответствующую функцию.
4В ОС Windows окно - это некоторая структура, которая может получать сообщения, и от которого может осуществляться посылка некоторых специальных сообщений. Для посылки большинства сообщений окна-отправителя не требуется. При переносе под UNIX окна возможно будут заменены очередями.
5Без потери общности можно предположить, что не метод объекта вызывается из откуда-нибудь, а один объект вызывает метод другого.
6Вообще говоря, байт может иметь и другую разрядность, например состоять из девяти бит.
7В языке Object Pascal внутри тела функции имеется предопределенная переменная Result типа, возвращаемого функцией.
8Насчет наглядности и удобности можно спорить, поэтому были оставлены и первоначальные определения функций.
9Такой тип определяется через примерно такую конструкцию: FooClass = class of Foo; .
10Так как все экземпляры динамические, то переменная типа класса в языке Object Pascal всегда является указателем на экземпляр этого класса. При обращении к методам и полям класса не нужно разыменовывать ссылку с помощью знака ^. Соответственно и при передаче объекта как параметра функции и процедуре передается всегда указатель.
11Секция initialization ... end. в языке Object Pascal заменила секцию begin ... end. инициализации модуля, имеющуюся в языке Turbo Pascal. Также имеется и аналогичная секция finalization, которая выполняется при завершении программы.
12То есть если явно не указан базовый класс для нового класса, по умолчанию им является класс TObject, то есть Foo = class эквивалентно Foo = class(TObject).
13Delphiверсии 2.0 является 32-разрядным компилятором, использующую модель памяти FLAT, реализованную в Win 32. Поэтому все адреса передаются через 32-разрядные регистры процессоров i386 и выше.
14Следует иметь ввиду, что объектная ориентированность технологии OLE представляется несколько надуманной. Не вдаваясь в подробности реализации, следует иметь ввиду, что использование объектов в этой технологии имеет частично условный характер и практически никак не соотносится с иерархией классов/объектов в приложении. Но тем не менее эта технология оперирует понятиями объекта, почему продукт OLEnterprise и рассматривается в списке конкурентов.