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

Технология CORBA

Связывание с IDL

Спецификация CORBA регламентирует, во что должен превратиться каждый элемент языка IDL в процессе его трансляции в исходные тексты на языке программирования высокого уровня. Версия 2.2 спецификации CORBA расписывает подобные соответствия для C, C++, Smalltalk, Cobol, Ada и Java.Для примера рассмотрим подробнее трансляцию в Java.

Комментарии

Комментарии IDL никак не отражаются на сгенерированном Java-коде.

Имена

Результаты работы различных компиляторов могут различаться. В основном это касается добавления символов подчеркивания перед сгенерированными именами. Поскольку трансляция зависит от того, что за элемент языка IDL подвергается обработке, различается и количество файлов, получаемых в процессе генерации. Для пользовательских типов, например, будут созданы специальные файлы, имена которых заканчиваются суффиксами Helper и Holder.По спецификации, компилятор резервирует за собой следующие имена:

<тип> Helper, где <тип> - имя пользовательского типа;

<тип> Holder, где <тип> - имя пользовательского типа;

<базовыйТипJava>Holder, где <базовыйТипJava> - один из примитивных типов языка Java;

<интерфейс>Package, где <интерфейс> - имя интерфейса IDL.

Вспомогательные классы

Если программист описывает собственные типы, в результате их трансляции появляются два вспомогательных класса, имена которых состоят из имени типа с добавлением суффиксов Helper и Holder. Они необходимы для корректной работы с объектами. Helper содержит набор статических методов, выполняющих одни и те же рутинные действия. Класс с суффиксом Holder работает "оболочкой" для пользовательского типа, когда его нужно передать в качестве параметров операции объекта. Его генерация происходит не во всех случаях.

Класс Helper всегда имеет статические методы для чтения и записи данных в поток read () и write (), упаковки данных в тип Any и распаковки (методы insert () и extract() ), а также методы определения типа type() и его идентификатора в репозитарии id().

Класс Holder должен не только уметь записывать данные в поток методом _write(), читать их оттуда методом _ read () и возвращать код типа методом _ typecode (). В нем должна быть предусмотрена открытая переменная value, хранящая значение, и два конструктора: один - по умолчанию, т.е. без параметров, и второй - с параметром, инициализирующим переменную value.

Модули

Во время трансляции описания модулей превращаются в пакеты с теми же самыми именами, что и сами модули. Соответственно все описания типов внутри модулей после трансляции в классы и интерфейсы Java приобретают область видимости внутри сгенерированных пакетов. Если описания типов находятся за пределами модулей, то они транслируются в глобальный пакет Java,т. е. не включаются ни в один пакет. Для примера опишем следующий модуль:

module UserModule
{
typedef string UserType;
};

После его трансляции в выходном каталоге появится подкаталог с именем модуля, и в нем будут сохранены файлы, появившиеся в результате генерации исходных текстов для типа UserType. А в самих этих текстах появится строка принадлежности к пакету UserModule:

package UserModule;

Интерфейсы

В первую очередь создаются описания общедоступных интерфейсов Java,наследуемые от базового CORBA -интерфейса org.omg.CORBA.Object. Возьмем следующее описание на

IDL:

interface UserInterface
{
};

После компиляции создается следующий интерфейс на языке Java:

public interface UserInterface

extends org.omg.CORBA.Object
{

}

Внутри сгенерированного интерфейса описываются операции, которые компилятор обнаружит в IDL -файле. Для каждого из атрибутов интерфейса в них создаются описания методов чтения и записи. Если атрибут объявлен как readonly,для него генерируется лишь метод чтения. Исходный текст на IDL:

attribute float UserAttribute;

будет транслирован в следующие описания методов:

float UserAttribute();

void UserAttribute(float arg);

Если IDL -интерфейс наследуется от другого интерфейса, то в его описании на Java также будет присутствовать наследование.

Любой параметр операции с модификатором in транслируется в аргумент метода, имеющий соответствующий тип на языке Java.То же самое и с возвращаемым операцией значением. Параметры inout и out не могут транслироваться непосредственно в параметры методов на Java. Поэтому приходится пользоваться Holder классами. Программа-клиент подставляет в качестве параметра экземпляр подобного класса, в котором, как в контейнере, находится передаваемое значение. После передачи параметра по значению хранимые данные изменяются на серверной стороне и возвращаются клиенту, который "вскрывает контейнер" и извлекает новое значение аргумента. Например, показанная операция имеет параметр, объявленный как inout:

void userOperation(inout double param);

Компилятор IDL сделает из этого следующий метод на языке Java:

void userOperation(org.omg.CORBA.DoubleHolder param);

Такой подход, конечно, создает дополнительные сложности программиста: придется создать экземпляр Holder класса вручную.

Для интерфейса также создаются класс Helper и класс Holder. В первом из них дополнительно к методам, описанным в разделе "Вспомогательные классы", генерируется метод narrow(), с помощью которого делается приведение к оригинальному типу интерфейса. Дело в том, что программе при запросе ссылки на объект возвращается ссылка типа org.omg.CORBA.Object, которую необходимо привести к запрошенному типу перед использованием, что и делает narrow(). При невозможности произвести эту операцию происходит исключение CORBA::BAD PARAM.

Некоторые компиляторы (в том числе, idl2java из Visibroker) генерируют еще один метод. Он называется bind() и служит для получения ссылки на запрашиваемый объект. Этот метод не является частью спецификации CORBA.

Часто у программистов возникают сложности с пониманием того, как транслируются вложенные в описания интерфейсов конструкции. Кажется, что достаточно сгенерировать новый пакет с его именем и поместить в него внутреннее содержимое интерфейса. Однако, по спецификации CORBA,во избежание конфликтов имен нельзя создавать пакеты, имена которых совпадают с уже имеющимися именами. Поэтому решено задавать имена пакетов, добавляя к имени интерфейсов суффикс Package.

Опишем интерфейс, внутри которого объявляется пользовательский тип:

interface UserInterface
{
typedef any UserType;
};

В результате трансляции получится пакет UserInterfacePackage, в который и будут помещены все сгенерированные для пользовательского типа файлы, и все они будут начинаться с директивы:

package UserInterfacePackage;

Простые типы

Трансляция простых типов IDL приводит к появлению соответствующих идентификаторов, но уже имеющих Java -типы. В табл. 2.4 показано соответствие между ними: если данный тип может привести к возникновению исключительной ситуации, то она отмечена в графе "Исключения".

Программист должен быть осторожен, когда работает с целочисленными типами IDL,объявленными как unsigned. Как известно, в Java нет беззнаковых типов, и это может стать причиной ошибок. Следовательно, требуется позаботиться о соблюдении знаковости транслированного числа.

Holder классы для простых типов IDL определены в библиотеках, отвечающих за поддержку CORBA в пакете org.omg.CORBA. Имена этих классов начинаются с имени IDL -типа, написанного с заглавной буквы, и заканчиваются суффиксом Holder.

Таблица 2.4. Соответствие простых типов IDL типам Jav
Тип IDL Тип Java Исключения
boolean Boolean
char Char CORBA::DATA_CONVERSION
wchar Char
octet Byte
string java.lang.String CORBA::MARSHAL, CORBA::DATA_CONVERSION
wstring java.lang.String CORBA::MARSHAL
short Short
unsigned short Short
long Int
unsigned long int
long long long
Unsigned long long long
Float float
Double double
long double double (?)
Fixed java.math.BigDecimal CORBA::DATA_CONVERSION
Any org.omg.CORBA.Any CORBA::BAD_OPERATION
Константы

Константы внутри интерфейса.

Константы, декларируемые внутри интерфейса, транслируются в поля, описанные как public final static, т. е. константы Java.Например, строки:

interface UserInterface
{
const string constIntoInterface = "Hello!";
};

будут превращены компилятором java2idl в следующий исходный текст на языке Java:

public interface UserInterface extends com.inprise.vbroker.CORBA.Object  {

final public static java.lang.String
constIntoInterface =   (java.lang.String)   "Hello!";
}

Константы вне интерфейса

Константы, не включенные ни в один интерфейс, превращаются в интерфейс с тем же самым именем, что и константа. Внутри этого интерфейса помещается public static final поле с именем value. Например, следующий исходный текст:

module UserModule  
{
const string constIntoInterface = "Hello!";
};

будет транслирован следующим образом:

package UserModule;
public interface constIntoInterface  
{
final public static java.lang.String value = (java.lang.String)"Hello!";
}
Конструируемые типы

Перечислимые типы

В результате трансляции перечисления получается класс с модификаторами public final и именем, соответствующим имени, описанному в IDL-файле.Для каждого элемента выбора внутри класса создаются два статических члена. Первый является уникальной целочисленной константой, а второй - ссылкой на экземпляр перечисления, инициализированный константным значением для данного выбора. Заодно генерируется закрытый конструктор, инициализируемый целочисленным значением. Еще один метод, value (), возвращает целое число, которым инициализировано перечисление, а в дополнение к нему имеется метод получения элемента перечисления по заданному числу from_int (). При недопустимом значении параметра этого метода возникает исключение CORBA::BAD_ PARAM. Например, исходный текст:

enum UserEnum {  labelOne,   labelTwo,   labelThree  };

будет транслирован следующим образом:

public final class UserEnum 
{
public static final int  labelOne = 0, labelTwo = 1, labelThree = 2; 
public static final UserEnum labelOne = new UserEnum(labelOne); 
public static final UserEnum labelTwo = new UserEnum(labelTwo); 
public static final UserEnum labelThree = new UserEnum(labelThree); 
public int value() { return value; }
public static final UserEnum from int(int i) throws org.omg.CORBA.BAD_PARAM  
	{ switch (i)   
		{
		case _labelOne:
		return labelOne;
		case _labelTwo:
		return labelTwo;
		case _labelThree:
		return labelThree;
		default:
		throw new org.omg.CORBA.BAD_PARAM();
		}
	}
private UserEnum(int _value) 
	{
	this.value = value;
	}
private int _value;
}

Дискриминируемые объединения

Объединение, описанное на языке IDL, транслируется в Java -класс тем же самым именем и с модификаторами public final. Внутри можно также найти:

  • конструктор по умолчанию (без параметров);
  • метод чтения дискриминатора discriminator() ;
  • метод чтения для каждого варианта с именем, заимствованным из декларируемого варианта;
  • методы модификации значения для каждого декларируемого варианта;
  • методы модификации значения для каждого декларируемого варианта, который объявляется для нескольких меток case ;
  • метод default (), если в нем есть необходимость.

В качестве примера рассмотрим следующее дискриминируемое объединение:

enum UserEnum {Single,   Double, Any};
union UserUnion switch   (UserEnum)   {
case Single:
case Double:  wchar anySymbol; 
default:   any other;
};

и полученный в результате трансляции Java-код:

final public class UserUnion  
{
private java.lang.Object _object; 
private UserModule.UserEnum _disc;
private UserModule.UserEnum _defdisc = UserModule.UserEnum.Any; 
public UserUnion()   { }
public UserModule.UserEnum discriminator()
	{ return _disc;
	} 
public char anySymbol() {... } public org.omg.CORBA.Any other() {... } 
public void anySymbol(char value) {... }
public void anySymbol(UserModule.UserEnum disc, char value) {... } 
public void other(org.omg.CORBA.Any value) {... }
}

Все методы чтения генерируют исключительную ситуацию CORBA:: BAD_OPERATION, если читаемое значение не установлено. Поэтому желательно сначала вызывать метод descriminator (), чтобы ознакомиться с текущим типом хранимого значения. Если не указать в объединении метку default, компилятор сверит все имеющиеся метки со всеми возможными значениями дискриминанта. Если таких значений больше, чем ветвей case, будет сгенерирован еще один метод default () (или _ default () в случае конфликта имен), в котором хранимое значение будет установлено так, чтобы оно было за пределами дискриминанта. Если в предыдущем примере удалить строку с меткой default, то сгенерируется следующий метод:

public void _default() 
{ disc = defdisc; _object = null;
}
Антон Зубеков
Антон Зубеков

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