2.2 спецификации CORBA расписывает подобные соответствия для Cи, Cи++, Смолток, Кобол, Ада и Java. На этом занятии рассмотрим трансляцию в Java и постараемся иллюстрировать генерацию исходных текстов на примерах.
Комментарии
Если вы вставите комментарии в IDL-файл, то это никак не будет отражено в сгенерированных Java-файлах.
Имена
Результаты работы компилятора idltojava из Sun Java 2 и idl2java из Inprise Visbroker 3.4 могут различаться. В основном это касается добавления символов подчеркивания перед сгенерированными именами. Как говорится в спецификации, это делается для предотвращения коллизии имен. Хотя в принципе язык Java способен не допустить подобных коллизий за счет механизма пакетных имен, компилятор из Java 2 добавит символ ?_?, руководствуясь девизом «как бы чего не вышло». А вот Visibroker 3.4 вообще обходится без изменений и оставляет идентификаторы такими, как они есть.
Поскольку трансляция зависит от того, что за элемент языка IDL подвергается обработке, различается и количество файлов, получаемых в процессе генерации. Для пользовательских типов, например, будут созданы специальные файлы, имена которых заканчиваются суффиксами Helper и Holder.
Еще один интересный момент связан с зарезервированными именами. По спецификации, компилятор резервирует за собой следующие имена:
<тип>Helper, где <тип> — имя пользовательского типа; <тип>Holder, где <тип> — имя пользовательского типа; <базовыйТипJava>Holder, где <базовыйТипJava> — один из примитивных типов языка Java; <интерфейс>Package, где <интерфейс> — имя интерфейса IDL.
Однако эксперименты по компиляции показали, что и idltojava и idl2java одинаково хорошо компилируют зарезервированные слова, избегая конфликтов. Тем не менее
написанные в спецификации правила следует соблюдать! Иначе вы рискуете попасть в сложную ситуацию при переходе с одного компилятора IDL на другой или в случае ужесточения правил в следующих версиях спецификации CORBA. Никто тогда не сможет поручиться за то, что компилятор не сгенерирует имена, совпадающие с вашими. Подобные ошибки могут быть трудно уловимыми!
Структурные элементы и вспомогательные классы
В отличие от двух предыдущих занятий, мы избрали иную последовательность рассмотрения элементов, потому что знание трансляции структурных элементов, а также назначения вспомогательных классов критичны для понимания остального материала.
Вспомогательные классы (Helper и Holder)
Если программист описывает собственные типы, в результате их трансляции появляются два вспомогательных класса, имена которых состоят из имени типа с добавлением суффиксов Helper и Holder. Они необходимы для корректной работы с объектами. Helper содержит «джентльменский» набор статических методов, упрощающих жизнь программисту, поскольку генерируемые методы выполняют одни и те же рутинные действия. Класс с суффиксом Holder работает «оболочкой» для пользовательского типа, когда его нужно передать в качестве параметров операции объекта. Да и генерация его происходит не во всех случаях — см. ниже «Описание типа (typedef)».
Класс-Helper всегда имеет статические методы для чтения и записи данных в поток read() и write(), упаковки данных в тип Any и распаковки (методы insert() и extract()), а также методы определения типа type() и его идентификатора в репозитарии id(). Прочие методы — от лукавого. Например, компилятор idl2java из Visibroker создает метод _orb(), который возвращает ссылку на инициализированный экземпляр ORB. После работы idltojava из Java 2 такой метод не возникает, зато появляется скрытый конструктор, не позволяющий создавать экземпляры объекта директивой new.
С классом-Holder дело обстоит несколько сложнее. Он должен не только уметь записывать данные в поток методом _write(), читать их оттуда методом _read() и возвращать код типа методом _typecode(). В нем должна быть предусмотрена открытая переменная value, хранящая значение, и два конструктора: один — по умолчанию, т.е. без параметров, и второй — с параметром, инициализирующим переменную value.
Модули
Модули служат для группировки типов, интерфейсов и прочих элементов, логически связанных друг с другом. Во время трансляции описания модулей превращаются в пакеты с теми же самыми именами, что и сами модули. Соответственно все описания типов внутри модулей после трансляции в классы и интерфейсы Java приобретают область видимости внутри сгенерированных пакетов. Если описания типов находятся за пределами модулей, то они транслируются в глобальный пакет Java, т. е. не включаются ни в один пакет.
Для примера опишем следующий модуль:
module UserModule { typedef string UserType; };
После его трансляции в выходном каталоге появится подкаталог с именем модуля, и в нем будут сохранены файлы, появившиеся в результате генерации исходных текстов для типа UserType. А в самих этих текстах появится строка принадлежности к пакету UserModule:
package UserModule;
Интерфейсы
Трансляция интерфейсов происходит намного сложнее, чем трансляция модулей. В первую очередь создаются описания общедоступных интерфейсов Java, наследуемые от базового CORBA-интерфейса org.omg.CORBA. Object. Однако Visibroker генерирует интерфейс, наследуемый от com.inprise.vbroker.CORBA.Object, который в свою очередь является наследником org.omg.CORBA. Object. Возьмем следующее описание на IDL:
interface UserInterface { };
После компиляции программой idltojava из Java 2 создается следующий интерфейс на языке 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 (см. разделы «Простые типы» и «Описание типа (typedef)»). То же самое и с возвращаемым операцией значением. А вот параметры inout и out — особый случай. Они не могут транслироваться непосредственно в параметры методов на таком языке высокого уровня, как Java. Поэтому приходится пользоваться Holder-классами. Программа-клиент подставляет в качестве параметра экземпляр подобного класса, в котором, как в контейнере, находится передаваемое значение. После передачи параметра по значению хранимые данные изменяются на серверной стороне и возвращаются клиенту, который «вскрывает контейнер» и извлекает новое значение аргумента. Например, показанная операция имеет параметр, объявленный как inout:
void userOperation(inout double param);
Компилятор IDL сделает из этого следующий метод на языке Java:
void userOperation(org.omg.CORBA.DoubleHolder param);
Как видите, вместо изначально задуманного типа параметра нужно подставлять экземпляр Holder-класса. Такой подход, конечно, создает дополнительные сложности программиста: придется создать экземпляр такого класса вручную. Но к этому быстро привыкаешь.
Для интерфейса также создаются класс-Helper и класс-Holder. Класс-Helper дополнительно к методам, описанным в разделе «Вспомогательные классы (Helper и Holder)», генерируется метод narrow(), с помощью которого делается приведение к оригинальному типу интерфейса. Дело в том, что программе при запросе ссылки на объект возвращается ссылка типа org.omg.CORBA.Object, которую необходимо привести к запрошенному типу перед использованием, что и делает narrow(). При невозможности произвести эту операцию происходит исключение CORBA::BAD_ PARAM.
Еще один метод генерируется idl2java из Visibroker. Он называется bind() и служит для получения ссылки на запрашиваемый объект. Поскольку bind() не является частью спецификации CORBA, многие компиляторы игнорируют его создание. И даже у idl2java имеется опция, отключающая создание bind().
Часто у программистов возникают сложности с пониманием того, как транслируются вложенные в описания интерфейсов конструкции. Кажется, что достаточно сгенерировать новый пакет с его именем и поместить в него внутреннее содержимое интерфейса. Однако, по спецификации CORBA, во избежание конфликтов имен нельзя создавать пакеты, имена которых совпадают с уже имеющимися именами. Поэтому решено задавать имена пакетов, добавляя к имени интерфейсов суффикс Package.
Опишем интерфейс, внутри которого объявляется пользовательский тип:
interface UserInterface { typedef any UserType; };
В результате трансляции получится пакет UserInterfacePackage, в который и будут помещены все сгенерированные для пользовательского типа файлы, и все они будут начинаться с директивы:
package UserInterfacePackage;
Простые типы
Трансляция простых типов IDL приводит к появлению соответствующих идентификаторов, но уже имеющих Java-типы. В табл. 1 показано соответствие между ними: если данный тип может привести к возникновению исключительной ситуации, то она отмечена в графе «Исключения».
Пока не все из приведенных в табл. 1 IDL-типов поддаются трансляции, поэтому они показаны курсивом. К примеру, как мы уже знаем из предыдущих занятий, тип fixed только заявлен в спецификации, но реализован будет позже. Частично это касается и типа long double, который объявлен в спецификации как нереализованный. Если попробовать компилятор idltojava из Java 2, то вы получите сообщения об ошибке. А вот idl2java из Visibroker 3.4 транслирует его в Java-тип double на свой страх и риск, поскольку в спецификации CORBA 2.2 ничего не сказано про предполагаемый тип, который должен появиться в результате трансляции. Возможно, трансляция long double будет производиться в такой класс Java, как java.math.BigFloat.
Программист должен быть осторожен, когда работает с целочисленными типами IDL, объявленными как unsigned. Как известно, в Java нет беззнаковых типов, и это может стать причиной казусов. Следовательно, требуется позаботиться о соблюдении знаковости транслированного числа.
Как уже говорилось в предыдущем разделе, для каждого параметра, объявленного как inout или out, генерируется подстановка Holder-класса. Простые типы IDL не исключение. Только для них Holder-классы предопределены изначально и «зашиты» в библиотеки, отвечающие за поддержку CORBA в пакете org.omg.CORBA. Имена этих классов начинаются с имени IDL-типа, написанного с заглавной буквы, и заканчиваются, как и положено, суффиксом Holder (табл. 2).
Константы
Трансляция констант подчиняется правилам, описанным в предыдущем разделе. Однако для констант некоторых типов IDL имеются тонкие моменты, связанные с областью описания. О них стоит поговорить отдельно.
Константы внутри интерфейса
Константы, декларируемые внутри интерфейса, транслируются в поля, описанные как 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 поле c именем value. Например, следующий исходный текст:
module UserModule { const string constIntoInterface = ?Hello!?; };будет транслирован следующим образом:
package UserModule; public interface constIntoInterface { final public static java.lang.String value = (java.lang.String)?Hello!?; }
Ходят слухи, что в спецификации CORBA 3 трансляция констант вне интерфейсов будет происходить иначе.
Конструируемые типы
Как вы уже знаете, к конструируемым типам IDL относятся структуры, дискриминируемые объединения и энумераторы. Их трансляция довольно сложна и требует навыка работы с полученными результатами.
Структуры
Тип struct во время компиляции транслируется в класс Java с модификаторами final и public. Имя полученного класса совпадает с именем структуры. В классе объявляются переменные-члены для каждого объявленного в IDL поля структуры. Разумеется, тип переменных-членов уже относится к языку Java и выясняется в процессе трансляции полей структуры. Так же внутри полученного класса декларируются два конструктора: один — по умолчанию, т. е. без параметров, и другой — конструктор инициализации с параметрами для инициализации переменных-членов. Visibroker заодно создает метод toString(), возвращающий строку, в текстовой форме отражающую содержимое полей класса.
Например, объявлена следующая структура:
struct UserStructure { any descriptor; Object reference; };
После трансляции с помощью idltojava из Java 2 полученный класс UserStructure.java имеет следующий вид:
public final class UserStructure { public org.omg.CORBA.Any descriptor; public org.omg.CORBA.Object reference; public UserStructure() { } public UserStructure(org.omg.CORBA.Any __descriptor, org.omg.CORBA.Object __reference) { descriptor = __descriptor; reference = __reference; } }
Вдобавок к основному классу генерируются стандартные класс-Helper и класс-Holder.
Дискриминируемые объединения
Объединение, описанное на языке 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; };
А вот схематичный результат, сгенерированный idl2java из Visibroker:
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, то Visibroker сгенерирует следующий метод:
public void _default() { _disc = _defdisc; _object = null; }
Замечательная ловушка подложена тем, кто невнимательно читает спецификации. Маленький незамеченный абзац заставил в свое время автора поломать голову над, казалось бы, бессмысленной ошибкой, звучащей примерно так: «Не могу установить значение объединения по умолчанию». Подобную незадачу комментирует следующий фрагмент спецификации: «Нельзя определять объединение с меткой default, если набор case-меток полностью покрывает все возможные значения дискриминанта. Вся ответственность за это лежит на генераторе Java-кода (IDL-компиляторе или другом инструменте), который должен определить подобную ситуацию и не допустить генерацию неверного кода».
Так что «ругань» со стороны компилятора idl2java из набора Visibroker вполне мотивирована, чего не скажешь об idltojava, входящем в состав Sun Java 2. Вместо того чтобы выдать сообщение об ошибке, он по широте душевной создал-таки исходные тексты, игнорирующие замечания спецификации CORBA.
Как и для других сложных типов, для объединений создаются стандартные классы Helper и Holder.
Энумераторы
В результате трансляции энумератора получается класс с модификаторами 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; }
Сложность полученного в процессе трансляции исходного текста объясняется просто — должен существовать только один экземпляр энумератора, а точнее — по одному экземпляру энумератора для каждого элемента выбора. Поэтому конструктор и закрыт, чтобы не допустить создания экземпляра командой new. Когда в своей программе вы пишете что-нибудь вроде:
UserEnum myEnum = UserEnum.labelTwo;
Java создает экземпляр энумератора и инициализирует его поле _value константным значением UserEnum._ labelTwo, т. е. числом 1.
Классы Helper и Holder генерируются и для энумераторов.
Последовательности и массивы
Последовательности не создают в процессе трансляции исходного текста какого-либо исходного текста, но значительно усложняют класс-Helper и класс-Holder. Класс-Holder теперь содержит массив с именем value для хранения элементов последовательности, а в методах класса-Holder идет проверка диапазона передаваемого массива на предмет выхода за границы. Например, при трансляции:
typedef sequence UserSequence;
вызывает генерацию следующего массива в Holder-классе:
public byte[] value;
и несколько мест, где происходит проверка границ массива:
abstract public class UserSequenceHelper { ... public static byte[] read(org.omg. CORBA.portable. InputStream_input) { ... if(_length3 > 128) { throw new org.omg.CORBA.BAD_PARAM (?Sequence exceeded bound?); } ... } public static void write(org.omg. CORBA.portable. OutputStream _output, byte[] value) { if(value.length > 128) { throw new org.omg.CORBA.BAD_PARAM (?Sequence exceeded bound?); } ... } ... }
Трансляция массивов во многом похожа на трансляцию ограниченных последовательностей. Разница лишь в проверке границ. Если ограниченные последовательности, как показано выше, предполагают проверку на выход за границы размера, то массив проверяется на четкое сооветствие размеру:
... public static void write(org.omg. CORBA.portable. OutputStream _output, byte[] value) { if(value.length != 128) { throw new org.omg.CORBA. BAD_PARAM(?Invalid array length?); } _output.write_octet_array (value, 0, value.length); } ...
Массивы и последовательности — элементы, для которых генерируются не только Helper-, но и Holder-классы.
Исключения
Поскольку исключения имеют схожее со структурой строение, любое исключение, описанное пользователем на IDL, транслируется в класс с модификатором final public, ведущим свою родословную от org.omg.CORBA. UserException. Системные исключения CORBA, наоборот, наследуются от исключения java.lang. Runtime Exception, которое, как правило, не перехватывается.
Сгенерированный класс содержит по переменной для каждого описанного в IDL поля и два конструктора: по умолчанию (без параметров) и инициализации. Следующий пример:
exception UserException { string why; octet errorCode; };
показывает, как происходит трансляция исключения компилятором idltojava из Java 2:
public final class UserException extends org.omg.CORBA.UserException { public String why; public byte errorCode; public UserException() { super(); } public UserException(String __why, byte __errorCode) { super(); why = __why; errorCode = __errorCode; } }
В CORBA имеется ряд предопределенных системных исключений, каждое из которых косвенно наследует класс java.lang.RuntimeException через другой класс org.omg.CORBA.SystemException (табл. 3).
Описание типа (typedef)
Поскольку оператор typedef создает псевдонимы для уже имеющихся типов, то во время трансляции любое упоминание пользовательского типа, полученного c помощью typedef (за исключением последовательностей и массивов), приведет к подстановке оригинального типа. Напишем такой фрагмент на языке IDL^
typedef any UserType; interface UserInterface { attribute UserType var; };
Трансляция компилятором idl2java из Visibroker произведет следующий исходный текст:
public interface UserInterface extends com.inprise.vbroker.CORBA.Object { public void _var( org.omg.CORBA.Any _var ); public org.omg.CORBA.Any _var(); }
Как видите, от типа UserType не осталось и следа, его место занял оригинальный тип any, точнее, его производное — Java-класс org.omg.CORBA.Any.
По спецификации CORBA, на каждый пользовательский тип должен быть сгенерирован Helper-класс. И только Visibroker создает еще и Holder-класс.
Знай свой компилятор idl
Действительно, читая данное описание, можно подумать, будто каждый компилятор IDL делает то, что ему вздумается. Однако это не так. Хотя различия и присутствуют, они не столь страшны. Когда-нибудь все придет к общему знаменателю, но пока что, транслируя IDL в язык высокого уровня, неплохо ознакомиться с теми именами, которые получатся в результате. Решая всевозможные задачи, приглядитесь к «характеру» компилятора.
Таблица 1. Соответствие между IDL- и Java-типами | ||
Тип 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 |
Таблица 2. Имена Holder-классов, отвечающие за поддержку CORBA | |
Holder-класс | Обслуживаемые типы IDL |
ByteHolder | octet |
CharHolder | char, wchar |
StringHolder | string, wstring |
ShortHolder | short, unsigned short |
IntHolder | long, unsigned long |
LongHolder | long long, unsigned long long |
FloatHolder | float |
DoubleHolder | double, long double (?) |
BooleanHolder | boolean |
AnyHolder | any |
ObjectHolder | Object |
Таблица 3. Стандартные системные исключения, определенные спецификацией CORBA | |
IDL Exception | Java Class Name |
CORBA::UNKNOWN | org.omg.CORBA. UNKNOWN |
CORBA::BAD_PARAM | org.omg.CORBA. BAD_PARAM |
CORBA::NO_MEMORY | org.omg.CORBA. NO_MEMORY |
CORBA::IMP_LIMIT | org.omg.CORBA. IMP_LIMIT |
CORBA::COMM_FAILURE | org.omg.CORBA. COMM_FAILURE |
CORBA::INV_OBJREF | org.omg.CORBA. INV_OBJREF |
CORBA::NO_PERMISSION | org.omg.CORBA. NO_PERMISSION |
CORBA::INTERNAL | org.omg.CORBA. INTERNAL |
CORBA::MARSHAL | org.omg.CORBA. MARSHAL |
CORBA::INITIALIZE | org.omg.CORBA. INITIALIZE |
CORBA::NO_IMPLEMENT | org.omg.CORBA. NO_IMPLEMENT |
CORBA::BAD_TYPECODE | org.omg.CORBA. BAD_TYPECODE |
CORBA::BAD_OPERATION | org.omg.CORBA. BAD_OPERATION |
CORBA::NO_RESOURCES | org.omg.CORBA. NO_RESOURCES |
CORBA::NO_RESPONSE | org.omg.CORBA. NO_RESPONSE |
CORBA::PERSIST_STORE | org.omg.CORBA. PERSIST_STORE |
CORBA::BAD_INV_ORDER | org.omg.CORBA. BAD_INV_ORDER |
CORBA::TRANSIENT | org.omg.CORBA. TRANSIENT |
CORBA::FREE_MEM | org.omg.CORBA. FREE_MEM |
CORBA::INV_IDENT | org.omg.CORBA. INV_IDENT |
CORBA::INV_FLAG | org.omg.CORBA. INV_FLAG |
CORBA::INTF_REPOS | org.omg.CORBA. INTF_REPOS |
CORBA::BAD_CONTEXT | org.omg.CORBA. BAD_CONTEXT |
CORBA::OBJ_ADAPTER | org.omg.CORBA. OBJ_ADAPTER |
CORBA::DATA_CONVERSION | org.omg.CORBA. DATA_CONVERSION |
CORBA::OBJECT_NOT_EXIST | org.omg.CORBA. OBJECT_NOT_EXIST |
CORBA::TRANSACTION-REQUIRED | org.omg.CORBA. TRANSACTION-REQUIRED |
CORBA::TRANSACTION-ROLLEDBACK | org.omg.CORBA. TRANSACTION-ROLLEDBACK |
CORBA::INVALIDTRANS-ACTION | org.omg.CORBA. INVALIDTRANS-ACTION |