CORBA (Common Object Request Broker Architecture) is a standard architecture of a remote procedure call framework that supports heterogeneous object oriented applications. The CORBA standard has evolved through several major revisions, the text in this section is mostly relevant for the later 2.x and early 3.x versions.
The interface definition language is used to describe types used by CORBA, from the basic types of individual arguments to the complex types of interfaces and objects. The language is similar in syntax to C++.
The integer types are short, long and long long for signed integer numbers of 16, 32 and 64 bits and unsigned short, unsigned long and unsigned long long for their unsigned counterparts.
16 bit signed integer
32 bit signed integer
64 bit signed integer
16 bit unsigned integer
32 bit unsigned integer
64 bit unsigned integer
Values.
18, 022, 0x12, 0X12
Constants.
const short aShortConstant = 6 * 7;
The floating point types are float, double and long double for ANSI/IEEE 754-1985 single precision, double precision and double extended precision floating point numbers.
24 bit signed fraction, 8 bit signed exponent
53 bit signed fraction, 11 bit signed exponent
113 bit signed fraction, 15 bit signed exponent
Values.
3.14, 12.34e5, 1.2E-4
Constants.
const float aFloatConstant = 3.141593;
The character types are char for a single character in a single-byte character set and wchar for a single character in a multiple-byte character set. The interface definition language itself uses ISO 8859-1 Latin 1.
character in single-byte character set
character in multiple-byte character set
Values.
'a', '\n', '\000', '\x12'
Constants.
const char aTab = '\t'; const wchar aWideTab = L'\t';
The logical type is boolean with values of true and false.
logical value
Values.
TRUE, FALSE
Constants.
const boolean aTrueValue = TRUE; const boolean aFalseValue = FALSE;
The special types are octet for 8 bits of raw data and any for a container of another arbitrary type.
A structure represents a classical compound type with named members that all contain a value.
An exception is a structure that can be returned as an exceptional result of an operation. A number of standard exceptions is defined. Note there is no inheritance in exception declarations, however, language mappings do add inheritance to make it easier to catch standard exceptions.
Declaration.
exception anException { string reason; string severity; };
Standard System Exception.
exception COMM_FAILURE { unsigned long minor; completion_status completed; };
A union represents a classical compound type with named members out of which one contains a value. A discriminator is used to determine which of the members contaisn the value.
Declaration.
union aSillyUnion switch (short) { case 1 : long aLongValue; case 2 : float aFloatValue; default : string aStringValue; };
An enum represents a classical enumerated type with distinct identifiers stored as 32 bit unsigned integers.
An array is a container for a fixed number of items of the same type addressed by integer indices.
A sequence is a container for a variable number of items of the same type addressed by integer indices. The maximum number of items in the container can be limited explicitly.
Declaration.
typedef sequence<long,10> aBoundedVector; typedef sequence<long> anUnboundedVector;
A string is a sequence of char items. A wstring is a sequence of wchar items.
Declaration.
typedef string<10> aBoundedString; typedef string anUnboundedString;
Constants.
const string aHello = "Hello\n"; const wstring aWideHello = L"Hello\n";
A fixed point type represents a fixed point number of upto 31 significant digits.
An interface type represents an object that is passed by reference and accessed remotely. The declaration of an interface type can specify multiple interface inheritance, attributes and operations. Apart from this, the declaration also creates a lexical scope within which other declarations can appear.
Declaration.
abstract interface aParentInterface { attribute string aStringAttribute; short aMethod (in long aLongArgument, inout float aFloatArgument); } interface aChildInterface : aParentInterface { readonly attribute short aShortAttribute; oneway void aOnewayMethod (in long anArgument); void aTwowayMethod () raises anException; }
Keywords.
interface not invoked remotely
runtime determines passing semantics
best effort delivery
attribute without setter
In some situations, it might be useful to have an interface type that can represent both an object passed by reference and an object passed by value. This is possible when the interface is denoted as abstract.
It is also possible to use interface types to describe objects that are not invoked through CORBA, the interface types are then denoted as local.
A value type represents an object that is passed by value and accessed locally. The declaration of a value type can specify single value type inheritance, single interface and multiple abstract interface support, attributes with private or public visibility, operations and initializers. Apart from this, the declaration also creates a lexical scope within which other declarations can appear.
Declaration.
valuetype aChildValue : truncatable aParentValue, supports anInterface { private short aShortMember; public aParentValue aValueMember; factory aFactory (in string anArgument); short aLocalMethod (in long aLongArgument, in float aFloatArgument); }
Keywords.
custom marshalling
base type not instantiated
state compatible with parent
value used by clients
value used by implementation
portable initializer
A value type can support multiple abstract interfaces but only a single interface that is not abstract. When used as an instance of one of the supported abstract interfaces, the value type is passed by value. When used as an instance of the supported interface that is not abstract, the value type is passed by reference.
When an object is passed by value, it might happen that an implementation of its type is not available to the receiver, but an implementation of its parent type is. When a value type is denoted as truncatable, its implementation is considered compatible with the implementation of its parent to the degree that the state of the type can be truncated to the portion inherited from its parent and used by its parent.
A value type that is declared custom will rely on user defined marshalling implementation. A custom value type may not be truncatable.
The section on language mapping discusses C++ and Java as two major examples. For mostly historical reasons, some mapping constructs do not rely on all the latest features of the target languages, making the language mapping more portable but perhaps potentially less elegant.
Since the goal of the text is to illustrate the issues encountered in language mapping, it outlines the mapping for selected representative types only. Mapping of other types is roughly analogous. Note how in C++, the mapping can use overloading to achieve syntactically simple constructs, but struggles to cope with memory management. In contrast, the mapping to Java sometimes struggles to map types without native counterparts, but memory management is completely transparent.
The goal of the integer types mapping is to use native types with matching precision. The use of native types means no conversion is necessary during argument passing. The requirement of matching precision is obviously necessary for correctness.
C++. Because the early versions of the language do not standardize the precision of native integer types, the mapping introduces CORBA integer types that the implementation should use. These types are mapped to native integer types using typedef.
The mapping for C++11 uses standard integer types with explicit precision.
Java. Because the language does not provide unsigned integer types, the mapping uses signed integer types and indicates conversion errors by throwing an exception.
Because the language lacks the ability to pass mutable integer types by reference, special Holder
classes are defined for all integer types.
public final class IntHolder implements org.omg.CORBA.portable.Streamable { public int value; public IntHolder () { } public IntHolder (int o) { value = o; } public TypeCode _type () { return ORB.init ().get_primitive_tc (TCKind.tk_long); } public void _read (org.omg.CORBA.portable.InputStream in) { value = in.read_long (); } public void _write (org.omg.CORBA.portable.OutputStream out) { out.write_long (value); } }
The mapping of floating point types encounters similar problems as the mapping of integer types. These problems are also solved in a similar manner in both C++ and Java.
Besides the usual goal of using native types, mapping of character types also attempts to preserve the meaning of characters in presence of multiple potential encodings.
C++. Because the language does not standardize the encoding of native character types, the mapping assumes that platform specific information will be used to derive the appropriate encoding as necessary.
The language also lacks automated memory management.
Special var
classes and allocator methods are introduced.
class String_var { private: char *data; public: inline String_var () { data = 0; } inline String_var (char *p) { data = p; } inline String_var (const char *p) { if (p) data = CORBA::string_dup (p); else data = 0; } inline ~String_var () { CORBA::string_free (data); } inline String_var &operator = (char *p) { CORBA::string_free (data); data = p; return (*this); } inline operator char * () { return (data); } inline char &operator [] (CORBA::ULong index) { return (data [index]); } ... }
The var
classes and allocator methods help prevent memory management errors in common programming constructs.
void FunctionWithoutLeaks (void) { // All strings must be allocated using specific functions String_var vSmartPointer = string_dup ("A string ..."); // Except assignment from const string which copies const char *pConstPointer = "A const string ..."; vSmartPointer = pConstPointer; // Assignment releases rather than overwrites vSmartPointer = string_dup ("Another string ..."); // Going out of scope releases too throw (0); }
The mapping for C++11 provides reference types whose semantics is equal to that of std::shared_ptr and std::weak_ptr, available through the IDL::traits<T>::ref_type and IDL::traits<T>::weak_ref_type traits. The basic string type is std::string.
The paramount concern of the any type mapping is making it type safe, that is, making sure the type of the content is always known.
C++. The mapping relies on operator overloading and defines a class with accessor operators for all types that can be stored inside any. This includes accessors for user defined types.
class Any { public: // Types passed by value are easy void operator <<= (Any &, Short); Boolean operator >>= (const Any &, Short &); ... // Types passed by reference introduce ownership issues void operator <<= (Any &, const Any &); void operator <<= (Any &, Any *); ... // Types where overloading fails introduce resolution issues struct from_boolean { from_boolean (Boolean b) : val (b) { } Boolean val; }; struct from_octet { from_octet (Octet o) : val (o) { } Octet val; }; struct from_char { from_char (Char c) : val (c) { } Char val; }; ... void operator <<= (from_boolean); void operator <<= (from_octet); void operator <<= (from_char); ... struct to_boolean { to_boolean (Boolean &b) : ref (b) { } Boolean &ref; }; ... Boolean operator >>= (to_boolean) const; ... private: // Private operators can detect resolution issues unsigned char void operator <<= (unsigned char); Boolean operator >>= (unsigned char &) const; }
Operator overloading fails to distinguish IDL types that map to the same native type. This is true for example with the char and octet IDL types, which both map to the char native type. In such situations, wrapping in a distinct type is used.
The any type is assumed to own its content.
Any oContainer; // Small types can be stored easily Long iLongValue = 1234; Float fFloatValue = 12.34; oContainer <<= iLongValue; oContainer <<= fFloatValue; // Constant references have copying semantics const char *pConstString = "A string ..."; oContainer <<= pConstString; // Non constant references have adoption semantics String_var vString = string_dup ("A string ..."); oContainer <<= Any::from_string (vString, 0, FALSE); oContainer <<= Any::from_string (vString._retn (), 0, TRUE); // Some types need to be resolved explicitly Char cChar = 'X'; Octet bOctet = 0x55; oContainer <<= Any::from_char (cChar); oContainer <<= Any::from_octet (bOctet);
Any oContainer; // Small types can be retrieved easily Long iLongValue; Float fFloatValue; if (oContainer >>= iLongValue) ...; if (oContainer >>= fFloatValue) ...; // References remain owned by container const char *pConstString; if (oContainer >>= Any::to_string (pConstString, 0)) ...; // Some types need to be resolved explicitly Char cChar; Octet bOctet; if (oContainer >>= Any::to_char (cChar)) ...; if (oContainer >>= Any::to_octet (bOctet)) ...;
Java.
The mapping defines a class with accessor methods for all standard types.
To keep the any
class independent of user defined types, methods for inserting and extracting a user defined type are implemented by helper classes associated with that type.
The mapping of structures and exceptions uses the corresponding object types.
C++. A structure is assumed to own its content.
An exception is equipped with a method to throw its most derived type.
The paramount concern of the union type mapping is making it type safe, that is, making sure the type of the content is always known.
C++. The mapping defines a class with accessor methods for all types that can be stored inside the union. Each setter method also sets the discriminator as appropriate. Each getter method also tests the discriminator.
class AUnion { public: ... void _d (Short); // Set discriminator Short _d() const; // Get discriminator void ShortItem (Short); // Store ShortItem and set discriminator Short ShortItem () const; // Read ShortItem if stored void LongItem (Long); // Store LongItem and set discriminator Long LongItem () const; // Read LongItem if stored ... }
AUnion oUnion; Short iShortValue = 1234; Long iLongValue = 5678; // Storing sets discriminator oUnion.ShortItem (iShortValue); oUnion.LongItem (iLongValue); // Retrieving must check discriminator if (oUnion._d () == 1) iShortValue = oUnion.ShortItem (); if (oUnion._d () == 2) iLongValue = oUnion.LongItem ();
Java. The mapping defines a class with accessor methods for all types that can be stored inside the union. Each setter method also sets the discriminator as appropriate. Each getter method also tests the discriminator.
C++. The only catch to mapping the enum type is making sure of its size. This is achieved by defining an extra enum member that dictates the size.
Java. The mapping of the enum type should be type safe, that is, instances of different enum types should not be interchangeable among themselves or interchangeable with integer types. This, however, would prevent using instances of enum types in the switch statement. That is why the mapping uses a class to represent an enum but also defines integer constants corresponding to enum instances.
public class AnEnum { public static final int _red = 0; public static final AnEnum red = new AnEnum (_red); public static final int _green = 1; public static final AnEnum green = new AnEnum (_green); ... public int value () {...}; public static AnEnum from_int (int value) {...}; }
C++.
Because the language lacks variable length arrays, sequences are mapped to classes with an overloaded indexing operator.
Special var
classes and allocator methods are introduced.
class ASequence { public: ASequence (); ASequence (ULong max); ASequence (ULong max, ULong length, Short *data, Boolean release = FALSE); ... ULong maximum () const; Boolean release () const; void length (ULong); ULong length () const; T &operator [] (ULong index); const T &operator [] (ULong index) const; ... }
The mapping for C++11 provides reference types whose semantics is equal to that of std::shared_ptr and std::weak_ptr, available through the IDL::traits<T>::ref_type and IDL::traits<T>::weak_ref_type traits. The basic sequence type is std::vector.
C++. The mapping relies on operator overloading and defines a class with common arithmetic operators. Because the language does not support fixed point constants, the mapping also adds a conversion from a string.
class Fixed { public: // Constructors Fixed (Long val); Fixed (ULong val); Fixed (LongLong val); Fixed (ULongLong val); ... Fixed (const char *); // Conversions operator LongLong () const; operator LongDouble () const; Fixed round (UShort scale) const; Fixed truncate (UShort scale) const; // Operators Fixed &operator = (const Fixed &val); Fixed &operator += (const Fixed &val); Fixed &operator -= (const Fixed &val); ... } Fixed operator + (const Fixed &val1, const Fixed &val2); Fixed operator - (const Fixed &val1, const Fixed &val2); ...
Java.
The mapping simply uses the BigDecimal
class.
Since the proxy should resemble an implementation of the interface that it represents, the mapping will generally use the native interface and object constructs of the target language in a straightforward manner. What makes proxies interesting are the subtle typing issues that arise.
C++.
The IDL interface is represented by a C++ class with virtual methods for IDL operations.
The proxy is a platform specific class that inherits from the interface class.
Safe type casting over remote types requires the addition of the narrow
method.
class AnInterface; typedef AnInterface *AnInterface_ptr; class AnInterface_var; class AnInterface : public virtual Object { public: typedef AnInterface_ptr _ptr_type; typedef AnInterface_var _var_type; static AnInterface_ptr _duplicate (AnInterface_ptr obj); static AnInterface_ptr _narrow (Object_ptr obj); static AnInterface_ptr _nil (); virtual ... AnOperation (...) = 0; protected: AnInterface (); virtual ~AnInterface (); ... }
Memory management issues are solved by introducing reference counting and var
classes.
class AnInterface_var : public _var { protected: AnInterface_ptr ptr; public: AnInterface_var () { ptr = AnInterface::_nil (); } AnInterface_var (AnInterface_ptr p) { ptr = p; } ... ~AnInterface_var () { release (ptr); } AnInterface_var &operator = (AnInterface_ptr p) { release (ptr); ptr = p; return (*this); } AnInterface_var &operator = (const AnInterface_var &var) { if (this != &var) { release (ptr); ptr = AnInterface::_duplicate (AnInterface_ptr (var)); } return (*this); } operator AnInterface_ptr & () { return (ptr); } AnInterface _ptr operator -> () const { return (ptr); } ... }
The mapping for C++11 provides reference types whose semantics is equal to that of std::shared_ptr and std::weak_ptr, available through the IDL::traits<T>::ref_type and IDL::traits<T>::weak_ref_type traits.
Casting to derived interfaces is supported through a IDL::traits<T>::narrow
method.
Java.
The IDL interface is represented by a Java interface with methods for IDL operations.
The proxy is a platform specific class that implements the Java interface.
Safe type casting over remote types requires the addition of the narrow
method.
Still more methods are present in a helper class that facilitates insertion and extraction to and from the any type together with the marshalling operations.
The standardization of the marshalling operations makes it possible to use proxy classes in a platform independent manner.
public interface AnInterfaceOperations { ... AnOperation (...) throws ...; } public interface AnInterface extends AnInterfaceOperations ... { } abstract public class AnInterfaceHelper { public static void insert (Any a, AnInterface t) {...} public static AnInterface extract (Any a) {...} public static AnInterface read (InputStream is) {...} public static void write (OutputStream os, AnInterface val) {...} ... public static AnInterface narrow (org.omg.CORBA.Object obj) {...} public static AnInterface narrow (java.lang.Object obj) {...} } final public class AnInterfaceHolder implements Streamable { public AnInterface value; public AnInterfaceHolder () { } public AnInterfaceHolder (AnInterface initial) {...} ... }
Where the mapping of the proxy selects the target type with transparency in mind, the mapping of the servant provides enough freedom in situations where strict typing constraints are not desirable. This is achieved by coupling servants to interfaces either by inheritance or by delegation.
C++. The servant mapping starts with a reference counted servant base class. The reference counting of servants is distinct from the reference counting of proxies.
class ServantBase { public: virtual ~ServantBase (); virtual InterfaceDef_ptr _get_interface () throw (SystemException); virtual Boolean _is_a (const char *logical_type_id) throw (SystemException); virtual Boolean _non_existent () throw (SystemException); virtual void _add_ref (); virtual void _remove_ref (); ... }
An abstract C++ class is generated for each IDL interface, the servant implementation can inherit from this abstract class and implement its methods as necessary. Alternatively, templates can be used to tie the servant implementation to a type that inherits from the abstract class.
class POA_AnInterface : public virtual ServantBase { public: virtual ... AnOperation (...) = 0; ... } template <class T> class POA_AnInterface_tie : public POA_AnInterface { public: POA_AnInterface_tie (T &t) : _ptr (t) { } ... ... AnOperation (...) { return (_ptr->AnOperation (...); } }
C++11. The servant mapping starts with a servant base class.
class Servant { public: virtual IDL::traits<CORBA::InterfaceDef>::ref_type _get_interface (); virtual bool _is_a (const std::string &logical_type_id); virtual bool _non_existent (); ... protected: virtual ~Servant (); }
An abstract C++ class is generated for each IDL interface, the servant implementation can inherit from this abstract class and implement its methods as necessary.
class _AnInterface_Servant_Base : public virtual Servant { public: virtual ... AnOperation (...) = 0; ... } class AnInterface_Servant : public virtual CORBA::servant_traits<AnInterface>::base_type { public: virtual ... AnOperation (...) override; }
Java. The servant mapping starts with a servant base class.
abstract public class Servant { final public Delegate _get_delegate () { ... } final public void _set_delegate (Delegate delegate) { ... } ... }
An abstract Java class is generated for each IDL interface, the servant implementation can inherit from this class and implement its methods as necessary. Alternatively, delegation can be used to tie the servant implementation to a type that inherits from the abstract class.
abstract public class AnInterfacePOA implements AnInterfaceOperations { public AnInterface _this () { ... } ... } public class AnInterfacePOATie extends AnInterfacePOA { private AnInterfaceOperations _delegate; public AnInterfacePOATie (AnInterfaceOperations delegate) { _delegate = delegate; } public AnInterfaceOperations _delegate () { return (_delegate); } public void _delegate (AnInterfaceOperations delegate) { _delegate = delegate; } public ... AnOperation (...) { return (_delegate.AnOperation (...); } }
C++. The language lacks both dynamic type creation and instance state access. The mapping therefore implements both, the type creation by factories and the state access by accessor methods. Custom marshalling interface is available for situations where generated marshalling code based on accessor methods is not appropriate.
class AValue : public virtual ValueBase { public: virtual void ShortItem (Short) = 0; virtual Short ShortItem () const = 0; virtual void LongItem (Long) = 0; virtual Long LongItem () const = 0; ... virtual ... AnOperation (...) = 0; } class OBV_AValue : public virtual AValue { public: virtual void ShortItem (Short) { ... }; virtual Short ShortItem () const { ... }; virtual void LongItem (Long) { ... }; virtual Long LongItem () const { ... }; ... virtual ... AnOperation (...) = 0; } class ValueFactoryBase { private: virtual ValueBase *create_for_unmarshal () = 0; ... } class AValue_init : public ValueFactoryBase { public: virtual AValue *AConstructor (...) = 0; ... }
Java. The language provides both dynamic type creation and instance state access. The mapping therefore only provides a custom marshalling interface for situations where generated marshalling code based on serialization is not appropriate.
It is also worth noting some broader aspects of argument passing.
C++. The language mapping attempts to minimize copying by preferring stack allocation to heap allocation whenever possible. The caller often allocates memory for values returned by the callee, otherwise stack allocation would not be possible. As an unfortunate complication, fixed size types and variable size types have to be distinguished.
The mapping for C++11 simplifies the argument passing rules. All primitive types are passed by value when input and by reference when output. All other types are passed by constant reference when input and by reference when output.
Java. Since the language does not allow passing some types by reference, holder classes are generated to solve the need for mapping output arguments.
The object adapter delivers requests to servants using a mapping from object ID values to servant references. An object ID is an opaque sequence of octets assigned to each object by the server. Incoming requests identify the target objects using their object ID.
The object adapter specification supports multiple configurations that govern the process of delivering requests to servants. Some configurations use an active object map to map object ID values to servant references. Other configurations use custom servant managers to determine the mapping. It is also possible to configure the threading model used to invoke servants. The configuration is set using policies.
local interface POA { POA create_POA (in string adapter_name, in POAManager manager, in CORBA::PolicyList policies); ThreadPolicy create_thread_policy (in ThreadPolicyValue value); LifespanPolicy create_lifespan_policy (in LifespanPolicyValue value); ServantRetentionPolicy create_servant_retention_policy (in ServantRetentionPolicyValue value); RequestProcessingPolicy create_request_processing_policy (in RequestProcessingPolicyValue value); ... }; local interface POAManager { enum State { HOLDING, ACTIVE, DISCARDING, INACTIVE }; State get_state (); void activate () raises (AdapterInactive); void hold_requests (in boolean wait_for_completion) raises (AdapterInactive); void discard_requests (in boolean wait_for_completion) raises (AdapterInactive); void deactivate (in boolean etherealize_objects, in boolean wait_for_completion); };
The threading model configuration is restricted to general categories. A particular object adapter implementation can provide more detailed threading model configuration. Typical configurations include the single threaded model and the leader-follower thread pool model.
Thread Policy Values.
calls to servants and managers are serialized
calls to servants are using single main thread
calls use arbitrary threading model
The object identity policies default to an automatically assigned system identity. Explicit configuration allows for custom identities, useful especially when object state is external, rather than encapsulated in the servant. Each servant can query the object identity associated with current request.
ID Uniqueness Policy Values.
servants have exactly one object ID
servants have at least one object ID
ID Assignment Policy Values.
object ID is assigned by application
object ID is assigned by object adapter
Implicit Activation Policy Values.
assign object ID on demand
do not assign object ID on demand
ObjectId activate_object (in Servant servant) raises (ServantAlreadyActive, WrongPolicy); void activate_object_with_id (in ObjectId oid, in Servant servant) raises (ObjectAlreadyActive, ServantAlreadyActive, WrongPolicy); void deactivate_object (in ObjectId oid) raises (ObjectNotActive, WrongPolicy); Object create_reference (in CORBA::RepositoryId ifc) raises (WrongPolicy); Object create_reference_with_id (in ObjectId oid, in CORBA::RepositoryId ifc); Object servant_to_reference (in Servant servant) raises (ServantNotActive, WrongPolicy); Servant reference_to_servant (in Object reference) raises (ObjectNotActive, WrongAdapter, WrongPolicy);
local interface Current { POA get_POA () raises (NoContext); ObjectId get_object_id () raises (NoContext); Object get_reference () raises (NoContext); Servant get_servant () raises (NoContext); };
A request can be delivered to a servant tracked in the active object map, a servant identified by one of the two servant manager types, or a default servant.
Servant Retention Policy Values.
keep track of active servants
do not keep track of active servants
Request Processing Policy Values.
only deliver to tracked servants
alternatively deliver to default servant
alternatively activate servants on demand
local interface ServantActivator : ServantManager { Servant incarnate (in ObjectId oid, in POA adapter) raises (ForwardRequest); void etherealize (in ObjectId oid, in POA adapter, in Servant servant, in boolean cleanup_in_progress, in boolean remaining_activations}; };
local interface ServantLocator : ServantManager { native Cookie; Servant preinvoke (in ObjectId oid, in POA adapter, in CORBA::Identifier operation, out Cookie cookie) raises (ForwardRequest); void postinvoke (in ObjectId oid, in POA adapter, in CORBA::Identifier operation, in Cookie cookie, in Servant servant); };
A request forwarding mechanism supports creating object references whose lifetime exceeds that of the server.
Lifespan Policy Values.
object references have lifetime of object adapter
object references have potentially unlimited lifetime
The network protocol is defined in two layers. The lower layer introduces the General Inter-ORB Protocol (GIOP), which defines the Common Data Representation (CDR), the message formats and the transport assumptions. The upper layer introduces the Internet Inter-ORB Protocol (IIOP), which specializes the lower layer for IP networks.
The Common Data Representation supports both byte orderings. Among interesting features are type codes, which serve to recursively describe the transported types where needed, and encapsulations, which serve to wrap already encoded data. Object references support multiple profiles, each profile describes one way to access the remote object.
Interface.
interface StockManager { attribute string stock_exchange_name; boolean add_stock (in string symbol, in double quote); void remove_stock (in string symbol, out double quote) raises (InvalidStock); };
Callback Mapping.
void sendc_get_stock_exchange_name ( in AMI_StockManagerHandler ami_handler); void sendc_set_stock_exchange_name ( in AMI_StockManagerHandler ami_handler, in string attr_stock_exchange_name); void sendc_add_stock ( in AMI_StockManagerHandler ami_handler, in string symbol, in double quote); void sendc_remove_stock ( in AMI_StockManagerHandler ami_handler, in string symbol); interface AMI_StockManagerHandler : Messaging::ReplyHandler { void get_stock_exchange_name ( in string ami_return_val); void get_stock_exchange_name_excep ( in Messaging::ExceptionHolder excep_holder); void set_stock_exchange_name (); void set_stock_exchange_name_excep ( in Messaging::ExceptionHolder excep_holder); void add_stock (in boolean ami_return_val); void add_stock_excep ( in Messaging::ExceptionHolder excep_holder); void remove_stock (in double quote); void remove_stock_excep ( in Messaging::ExceptionHolder excep_holder); };
Poller Mapping.
AMI_StockManagerPoller sendp_get_stock_exchange_name (); AMI_StockManagerPoller sendp_set_stock_exchange_name ( in string attr_stock_exchange_name); AMI_StockManagerPoller sendp_add_stock ( in string symbol, in double quote); AMI_StockManagerPoller sendp_remove_stock ( in string symbol); valuetype AMI_StockManagerPoller : Messaging::Poller { void get_stock_exchange_name ( in unsigned long timeout, out string ami_return_val); void set_stock_exchange_name ( in unsigned long timeout); void add_stock ( in unsigned long timeout, out boolean ami_return_val); void remove_stock ( in unsigned long timeout, out double quote) raises (InvalidStock); };
denote configurable properties
inherited in all interfaces
interfaces provided to the outside
interfaces required from the outside
events produced to the outside
events consumed from the outside
module DiningPhilosophers { interface IFork { void pick_up () raises (ForkNotAvailable); void release (); }; component AFork { provides IFork fork; }; eventtype PhilosopherStatus { public string name; public PhilosopherState state; public boolean has_left_fork; public boolean has_right_fork; }; component APhilosopher { attribute string name; // Receptacles for forks uses Fork left; uses Fork right; // Source for status publishes PhilosopherStatus status; }; component AnObserver { // Sink for status consumes PhilosopherStatus status; }; ... };
module Components { typedef string FeatureName; typedef sequence<FeatureName> NameList; valuetype PortDescription { public FeatureName name; public CORBA::RepositoryId type_id; }; ...
valuetype FacetDescription : PortDescription { public Object facet_ref; }; typedef sequence<FacetDescription> FacetDescriptions; interface Navigation { FacetDescriptions get_all_facets (); Object provide_facet (in FeatureName name) raises (InvalidName); FacetDescriptions get_named_facets (in NameList names) raises (InvalidName); ... }; ...
valuetype PublisherDescription : PortDescription { public SubscriberDescriptions consumers; }; typedef sequence<PublisherDescription> PublisherDescriptions; valuetype ConsumerDescription : PortDescription { public EventConsumerBase consumer; }; typedef sequence<ConsumerDescription> ConsumerDescriptions; PublisherDescriptions get_all_publishers (); PublisherDescriptions get_named_publishers (in NameList names) raises (InvalidName); ConsumerDescriptions get_all_consumers (); ConsumerDescriptions get_named_consumers (in NameList names) raises (InvalidName); ... };
uses AnInterface AReceptacle; consumes AnEvent ASink;
void connect_AReceptacle (in AnInterface connection) raises (AlreadyConnected, InvalidConnection); AnInterface disconnect_AReceptacle () raises (NoConnection); AnInterface get_connection_AReceptacle ();
AnEventConsumer get_consumer_ASink ();
module Components { ... interface Receptacles { Cookie connect (in FeatureName name, in Object connection) raises (InvalidName, InvalidConnection, AlreadyConnected, ExceededConnectionLimit); Object disconnect (in FeatureName name, in Cookie ck) raises (InvalidName, InvalidConnection, CookieRequired, NoConnection); ConnectionDescriptions get_connections (in FeatureName name) raises (InvalidName); ... }; ...
valuetype Cookie { private CORBA::OctetSeq cookieValue; }; valuetype SubscriberDescription { public Cookie ck; public EventConsumerBase consumer; }; typedef sequence<SubscriberDescription> SubscriberDescriptions; interface Events { void connect_consumer (in FeatureName emitter_name, in EventConsumerBase consumer) raises (InvalidName, AlreadyConnected, InvalidConnection); EventConsumerBase disconnect_consumer (in FeatureName source_name) raises (InvalidName, NoConnection); EventConsumerBase get_consumer (in FeatureName sink_name) raises (InvalidName); Cookie subscribe (in FeatureName publisher_name, in EventConsumerBase subscriber) raises (InvalidName, InvalidConnection, ExceededConnectionLimit); EventConsumerBase unsubscribe (in FeatureName publisher_name, in Cookie ck) raises (InvalidName, InvalidConnection); ... }; ... };
Remedy IT: CORBA Programmers Guide. http://www.remedy.nl/opensource/corbapg.html
OMG: CORBA Interface Definition Language Specifications. https://www.omg.org/spec/category/interface-definition-language
OMG: CORBA Language Mapping Specifications. https://www.omg.org/spec/category/language-mapping
OMG: CORBA Platform Specifications. https://www.omg.org/spec/category/corba-platform