Go to the previous, next section.

Using ILU with CORBA 2.0 C++

Introduction

This chapter describes the use of ILU with C++ in a manner compliant with the CORBA 2.0 C++ language mapping specification. (see http://www.omg.org/corba/corbiiop.htm) The use of ILU's original C++ support is deprecated.

Any function or type which is not part of the CORBA 2.0 specification has the prefix 'ilu'. It should be understood that use of 'ilu' prefixed functionality is not portable to other (non-ILU) CORBA implementations.

Some arguments or return values of functions (e.g. char*) have storage management requirements. Basically this revolves around whether the caller retains or gets ownership of the parameter and is therefore responsible for eventually releasing it, or if ILU takes or retains ownership, where it will be released at ILU's discretion. Any function parameter that becomes owned by ILU is marked with the comment /* ILUowned */ Any return value (or 'out' parameter) that remains under the ownership of ILU is similarly marked. Anything not so marked is not ILU's responsibility.

Note that ILU support for C++ does rely on having argument prototypes, all C++ library functions, and the capabilities of the C++ pre-processor.

Mapping ILU ISL to C++

The CORBA 2.0 C++ chapters 15 though 18 describes the mapping of OMG IDL to C++. For those elements of ISL for which there is a direct counterpart in IDL, the ISL component is mapped just as the IDL component is. Those ISL concepts with no IDL counterpart (marked with a '-' in the table below) have a mapping separately described in a following section.

ISL to IDL Correspondences


     ISL                    IDL
     -------------------------------------
     INTEGER                long
     SHORT INTEGER          short
     LONG INTEGER           -
     CARDINAL               unsigned long
     SHORT CARDINAL         unsigned short
     LONG CARDINAL          -
     BYTE                   octet
     BOOLEAN                boolean
     REAL                   double
     SHORT REAL             float
     LONG REAL              -
     CHARACTER              -
     SHORT CHARACTER        char
     PICKLE                 Any
     ARRAY                  array
     SEQUENCE               sequence
     RECORD                 struct
     UNION                  union
     OPTIONAL               -
     ENUMERATION            enum
     OBJECT                 object
     CString                string
     SEQUENCE OF CHARACTER  -
     EXCEPTION              -, exception
     INTERFACE              module

ISL Specific Mappings

The following table describes the mappings for ISL types that have no IDL counterparts. The C++ column gives the mapping modulo indirection and/or 'const' qualification dictated by parameter directionality (i.e., IN vs OUT vs INOUT vs return values).


     ISL                    C++
     --------------------------------------------------------------
     LONG INTEGER           iluLongInteger
     LONG CARDINAL          iluLongCardinal
     LONG REAL              iluLongReal
     CHARACTER              iluCharacter
     OPTIONAL X             X* for operation parameters;
                            'managed X*' for embedded types.
     SEQUENCE OF CHARACTER  iluCharacter*
     EXCEPTION              Any ISL exception that is
                            not a RECORD, maps to a subclass of
                            CORBA::UserException, that has a _value() 
                            member function which returns a value of 
                            the type associated with the exception.

Correspondence between C++ Types and Kernel Types

To provide a consistent naming scheme, in many cases, a type defined in the ILU kernel has been typedeffed to appear in C++ as the corresponding type name without the intervening underscore, and with the following letter capitalized, e.g. typedef ilu_cardinal iluCardinal;

C++ Classes Produced for an Object

The mapping for an ISL Object 'A' produces 3 C++ classes:

  1. The A C++ class, which has pure virtual member function declarations for each of A's methods. For each ISL Object supertype Si of ISL Object A, the C++ class A 'public virtual' inherits from the Si C++ class. If the ISL Object A has no supertypes, the A class 'public virtual' inherits from the iluObject class. [NOTE that an object described in IDL will implicity inherit from CORBA::Object (which in turn inherits from iluObject). The idl2isl translator automatically adds ilu.CORBA-Object as a SUPERTYPE.] This basically creates a C++ class hierarchy that is isomorphic to the ISL object type hierarchy, with each method being declared pure virtual. We refer to this hierarchy as the 'abstract object hierarchy'.

  2. The A_surrogate C++ class, which has virtual member function declarations for each of ISL Object A's non inherited methods. These member functions transfer requests to the true object. For each ISL Object supertype Si of ISL Object A, the C++ class A_surrogate 'public virtual' inherits from the Si_surrogate C++ class, and then 'public virtual' inherits from the C++ class A. (If the ISL Object A has no supertypes, the A_surrogate class 'public virtual' inherits only from the C++ class A.) This basically creates a C++ 'surrogate object hierarchy' that is isomorphic to the abstract object type hierarchy, with the addition that each X_surrogate class also inherits from its counterpart in the 'abstract object hierarchy'.

  3. An A_var C++ class as prescribed by the CORBA C++ mapping.

This mapping allows servers to be developed that do not contain surrogate stub code (if they don't need it), and also prevents the situation where a server method override is forgotten, resulting in surrogate stub code being called as it it were 'true' code.

For each ISL Object 'A' for which a true side implementation is to be developed, the true side implementer should define a class A_impl that inherits virtually from the C++ class A, and implements the actual true methods as member functions (in whatever manner is appropriate). The implementer is free to use delegation, implementation inheritance, whatever - the only restriction is that if a class B_impl inherits implementation from a class X, and class X inherits from a class in the abstract object hierarchy, (e.g. when X is A_impl), then X's inheritance from the abstract object hierarchy must be 'public virtual'.

Each produced C++ class e.g. A, will have a constructor C++: A ( char* pc_instance_handle, ilu_Server& r_an_ilu_server = iluServer::GetDefaultServer(), ILUCPP_BOOL b_within_object_table = ILUCPP_FALSE ) : iluObject ( A::m_ILUClassRecord, pc_instance_handle, r_an_ilu_server, b_within_object_table).

Misc. Mapping Details

Unions

In IDL, Union arms all have names, in ISL, the names may not be specified. If a name isn't specified for an arm, the name the stubber produces is the arm's typename, prefixed with '_', and suffixed with '_arm'.

For example,

TYPE someuniontype = short cardinal UNION	
        bar = 0, 1 END,   
        integer = DEFAULT	
END;

would produce the C++ names _bar_arm, and _integer_arm to reference the bar and integer arms.

Optionals

For procedure parameters, an ISL OPTIONAL type maps either to the same C++ type as its base type, if that base type is represented with an C++ pointer type, or to a pointer to that base type, if it is not represented with a C++ pointer type.

Additionally, all OPTIONAL types T have an associated C++ T_var.

For non-parameters (i.e., RECORD members, ARRAY and SEQUENCE elements) an ISL OPTIONAL type maps to a 'managed pointer', analagous to the mapping for non-parameter ISL OBJECT (CORBA interface) and ISL SEQUENCE OF SHORT CHARACTER (CORBA string). (This 'managed pointer' behaves similarly to T_var; however, CORBA does not allow compliant applications to use 'managed pointer' types directly, as the actual type is implementation-specific)

The following ISL and C++ code fragments illustrate:


     ISL

     TYPE SomeType   = ...
     TYPE MyOptional = OPTIONAL SomeType;

	 TYPE MyRec = RECORD
	     member: MyOptional
	 END;

	 TYPE MyArray = ARRAY OF 10 MyOptional;
	     member: MyOptional
	 END;


     C++

	 ...

     MyRec          myRec;
	 MyArray        myArray;
	 SomeType       st;
	 SomeType*      stPtr;
	 MyOptional     myOptional;  // MyOptional is equivalent to SomeType*
	 MyOptional_var stVar;

	 ...

	 myRec.member = myArray[0];        // free old myRec.member, deep copy
	 myArray[1]   = stVar;             // free old myArray[1], deep copy
	 myRec.member = stPtr;             // free old myRec.member, assume ownership
	 myRec.member = myOptional;        // free old myRec.member, assume ownership

	 myRec.member = &st;               // ILLEGAL - can't free &st
	 myRec.member = new SomeType(st);  // OK; free old myRec.member, assume ownership

	 stPtr = myArray[2];               // Simple pointer assignment, no copy
	 stVar = myRec.member;             // free old stVar, deep copy

The lifetime of recA.member and each myArray[n] are tied to recA and myArray, respectively; when an optional-containing variable goes out of scope or is destroyed, its optional members/elements are freed. Thus, the assignment myRec.member = &st in the example above is illegal and can lead to calamitous results when an attempt is made to free &st.

Exceptions

Any ISL exception that is not a RECORD, maps to a subclass of CORBA::UserException, that has a _value() member function which returns a value of the type associated with the exception.

ISL Asynchronous Methods

In IDL, methods may be ASYCHRONOUS. Asynchronous methods cannot have return values or raise exceptions. Hence, they result in a C++ member function declared to return void.

ISL Functional Methods

In IDL, methods may be FUNCTIONAL. In the C++ mapping, FUNCTIONAL is ignored. The ability to create custom C++ surrogates allows the implementation to decide what and how caching may be implemented on any method, as well as perform any other sorts of message 'filtering'.

ISL Collectible Objects

An ISL object being declared COLLECTIBLE has not effect on the mapping per-se. It will however cause ILU to adjust an object's reference count based on interest or dis-interest from clients.

Inheritence from CORBA::Object

If an ISL Object A has no supertypes, the A class 'public virtual' inherits from the iluObject class. An object described in IDL will implicity inherit from CORBA::Object (which in turn inherits from iluObject). (The idl2isl translator automatically adds ilu.CORBA-Object as a SUPERTYPE.) So, if you define an object in ISL, and do not explicitly declare ilu.CORBA-Object as a SUPERTYPE, you will not have the member functions of CORBA::Object available since you do not inherit from it.

Portability and Mapping Variations

The CORBA 2.0 C++ mapping allows for variations in the mapping depending on the C++ compilers support for Name Spaces, Exception Handling, and Run-Time Type information.

The ILU CORBA 2.0 C++ mapping implementation assumes that the C++ compiler supports exceptions. We also assume that the compiler supports RTTI should someone want to do narrowing within the exception hierarchy. [Given that ILU does not provide a Dynamic Invocation Interface, there's no real need to narrow exceptions anyway.]

During the configuration phase of ILU installation (or for Windows, per the definitions in `ILUSRC/runtime/kernel/iluwin.h') a determination is made as to whether or not to use namespaces, nested classes or underscores for IDL modules, based on the C++ compiler in use. [This can be overridden with the configuration option --with-cplusplus-mapping= switch to config.] This results in a C++ runtime that is constructed with one of these approaches in mind. Should a user decide to use a different mapping, this can be done by setting appropriate switches to the stubber, but you must bear in mind that the C++ runtime needs to be in correspondence, since the selection radically changes the names seen by a linker. Based on our knowledge (as of the date of this writing), of the degree of support/bugs for namespaces and nested classes, the following describes the IDL module mapping based on compiler:

C++ Compiler Module Mapping


     Compiler                 Mapping
     ---------------------------------------
     Microsoft Visual C++     underscores
     SunPro                   nested classes
     Gnu                      nested classes

To portably reference things in a interface when the stubber is directed to produce portable code, the stubber generates two macros, one for referring to things from outside the namespace (e.g. when defining a member function), and another for inside the namespace (e.g. inside a class declaration). The names of these macros are the interface name, and the interface name with a '_' (underscore) suffix. These macros expand to some other macros that are defined in the cppportability.hpp file.

To refer to things in the CORBA interface, one uses the CORBA macro. For example, CORBA(Boolean) b_my_result = ILUCPP_TRUE;

Because of possible variations in compiler support for Booleans, CORBA(Boolean) is defined as ILUCPP_BOOL, where ILUCPP_BOOL is defined as either an int (with ILUCPP_TRUE and ILUCPP_FALSE #defined as 1 and 0), or as a bool (with ILUCPP_TRUE and ILUCPP_FALSE #defined as true and false).

Concepts

Servers and Ports

In ILU there is a concept of an 'server object'. In the kernel this is the ilu_Server, which in the C++ runtime is encapsulated asn an iluServer object. This 'server' effectively forms a 'scope' in which true objects reside. This is why for example, and object lookup requires both the 'server' ID, and the object's instance handle - both are needed to uniquely denote an object.

Now a server has some number of 'ports'. A port is basically a means of communicating with the objects inside a server, using a particular combination of protocol and transport. For example, when create an iluServer, the constructor for iluServer automatically adds a port for the communication protocol and transport specified as constructor arguments. We can call iluServer::iluAddPort to have additional ports added. For example we may want to be able to communicate with the objects using sunrpc over tcp/ip, as well as http over tcp/ip. The iluServer has a notion of a default port. This is initially one as specified during construction, but this can be changed if when calling iluServer::iluAddPort we specify that this should become the default port. The default port is the one used when we ask for contact information for an object - that is, if we get the string binding handle for an object, the contact information in that string will reflect the default server port.

Object Tables

True objects may either be created ahead of time, or on an 'as needed' basis, i.e. when a call comes in involving them. The 'as needed' situation is made possible by 'object tables'. An iluServer may have associated with it (at construction time) an iluObjectTable object. When a call comes involving an object in that iluServer that the ILU doesn't already know about, the iluObjectTable object's iluObjectOfInstanceHandle gets called. It is the job of this function to create and return a new object with that instance handle. How it does this is specific to your application - it may read object state off a disk for example. In any event, one thing this function must do is ensure that when it calls the true objects constructor, that it sets the constructor's b_within_object_table argument to true. (Otherwise, internal locking constraints will be violated). While in the iluObjectOfInstanceHandle function, the associated iluServer's lock is held, and if the resulting object is expected to be of a COLLECTIBLE type, the global kernel mutex "gcmu" is also held. The fact that these locks are held somewhat restricts what an application can do inside this mapping procedure.

Threading

The ILU C++ support may be initialized to run in either threaded or non-threaded mode. In non threaded mode, a call to iluServer::iluRun member function results in a call to ILU's 'mainloop'. The mainloop basically sits waiting for an incoming request. When one comes in, the request is invoked. If the implementation of the invoked method makes a call to some other remote object, the mainloop is recursively entered while awaiting a reply. This allows additional requeste to come in and get serviced, preventing deadlock.

When intialized to run in threaded mode, ILU will run one thread for each incoming connection. Note that there may be multiple connections for a particular port (either from different clients, or from the same client who needed another connection because all the ones it had so far were busy at the time). In the case of a non-concurrent protocol (sunrpc, http, courier), the connection thread receives an incoming request, processes it itself, and then waits for the next request. In the case of a concurrent protocol (csunrpc, iiop), the connnection thread receives an incoming request, spawns a worker thread to carry out the request, and immediately goes back to waiting for more incoming requests.

The ILU C++ provides no special concurrency control for methods in your objects (to do so would be presumptive on our part). The method implementor must put appropriate locking in place if it is possible that multiple threads (or recursive mainloop invocations) might be running 'in' an object simultaneously.

Custom Surrogates

A surrogate is an object that is used to represent a remote object. When a method is invoked on a surrogate, the methods implementation in the surrogate transfers the call to the true object, and returns the result of this call, thus providing location transparency. There are times however when it is useful to have the surrogate's method implementation do more than just forward the call to the true object. An application may want a surrogate method implementation that caches the results of calls (potentially reducing network overhead), perform transformations on arguments, output diagnostic information, or whatever.

To facilitate this, the ILU C++ support allows an implementation to supply a function that is called when a surrogate for a particular object type is needed. The function iluCppRuntime::iluSetSurrogateCreator tells the C++ runtime what function to call when a surrogate for an object of the specified class is needed. This allows an implementation to subclass off a surrogate class, and write a new surrogate creation function that creates an instance of this new subclass. Call iluCppRuntime::iluSetSurrogateCreator after you've performed initialization, but before you do any operations which might create a surrogate of the specified class. It basically overwrites the default surrogate creation function set up by the surrogate stubs. It returns the old surrogate creator function, or NULL if was previously no surrogate creator for that class.

A surrogate creator function should at the minimum create an instance of a surrogate, call the instances member function iluAssociateKernelObject passing the iluKernelObject, and then return a pointer to the new instance.

String Binding Handle Manipulation

A String Binding Handle is a textual representation of an object reference. It contains the object's server id, instance id, information about how to contact the object, as well as other information. ILU C++ provides the functions iluCppRuntime::iluFormSBH, iluCppRuntime::iluFormSBHUsingContactInfo, and iluCppRuntime::iluParseSBH for constructing and parsing string binding handles. An object may be obtained from a string binding handle using iluObject::iluStringToObject and the string bindign handle of an object may be obtained by calling the iluObjectToString member function.

Simple Binding

When creating a service, there needs to be some way for clients to find out about the service. ILU C++ provides a simple mechanism to achieve this. Objects may be published, looked up, and their publications withdrawn using the appropriate member functions (iluPublish, iluLookup, iluWithdraw).

Object Activation

An true object is initially 'Active', which means that its ISL (or IDL as the case may be) defined methods may be invoked on it from outside its process (or from another language within that same process). An object may be made unavailable to outside calls, i.e. marked 'inactive' by calling its iluDeactivate member function. It may may be reactivated by calling its iluActivate member function.

An object is initially available from the outside until it is deactivated Objects that are involved in a call (i.e. sent or received as arguments, or the object the method is being invoked on) need to be protected from deletion for the duration of that involvement (for example, you don't want some thread deleting a true object when it's currently the target of a method call). The C++ runtime keeps track of what objects are involved in a call, and will attempt to prevent them from being deleted until the call is completed.

The application programmer needs to assist in this by calling, in the most specific destructor, iluDeactivate (inherited virtually from iluObject). iluDeactivate blocks any further incoming calls involving the object, and wait for any ongoing calls using the object to complete. Next the destructor should perform any object specific cleanup. Finally, the destructor in iluObject will break the association between the kernel object and this object, allowing the kernel object to be potentially freed.

Security

A client may set the Passport to be used on outgoing calls by creating and setting up an iluPassport, and then passing the passport in a call to iluPassport::iluSetPassport. This sets the passport to be used in the thread that made the call - i.e. iluPassport are on a per thread basis. Note that before your thread exits, you should either call iluSetPassport(NULL), or delete the iluPassport in use (assuming it's only in use for a single thread). The iluPassport (if any) currently setup for a thread can be retrieved by calling iluPassport::iluGetPassport.

A Server may obtain the iluPassport of the caller (if any) of a method by using the iluPassport::iluGetCallerPassport() function.

A iluServer may be constructed to use a particular identity by specifying a iluPassport as a constructor argument. This identity is used to identify the principal offering the service.

Static Initialization

The C++ Runtime normally relies on the static initializers in the files that the stubber generates to place initialization functions onto internal lists so that they will be invoked when the application calls iluCppRuntime::Initialize. However, it is not guaranteed by the ANSI C++ that static initializers are called upon the loading of a compilation unit. We have only had a report of one compiler that did not run the static initializers at load time (in fact, it was reported that it did not run them ever! - bug!?). We have observed static initialization at load time in Visual C++, SunPro and GNU compilers. In the event that you end up using a compiler that does not call the static initializers at load time, you can use the stubber defined initialization macros that are generated in the common header file for each interface.

(It should be pointed out that the CORBA 2.0 C++ Runtime does not suffer from the static initializer issues that plagued ILU's original C++ support. No ILU calls are actually made until iluCppRuntime::iluInitialize is called, allowing one to set up different mainloops, etc.)

Building an Application

Running the Stubber

To generate CORBA 2.0 C++ stubs from an ISL file, use the program cpp2-stubber. The stubber has the following usage:


     Usage: cpp2-stubber [arguments] Islfile [ISLFILE ...]
		 [arguments] can be any of the following:
		 [-nu|-underscores]
		 [-np|-portable]
		 [-nn|-nested]
		 [-ns|-namespaces]

The switches can be used to direct the stubber to produce code that using a specific module mapping, or portable module mapping. The default is whatever is found appropriate during the configuration phase of ILU installation (see "Portability and Mapping Variations"). Note that generating a specific (non-portable) mapping that does not match the platform default, is likely to cause errors at link time due to naming differences.

Stubber Generated Files

For an interface Foo the stubber generates:

`Foo-cpp.hpp' which contains the classes for the abstract object hierarchy, as well as any other declarations needed by both client and server.

`Foo-cpp.cpp', which contains any definitions needed by both client and server, which contains A has no supertypes, the A class 'public virtual' inherits from the iluObject class. An object described in IDL will implicity inherit from CORBA::Object (which in turn inherits from iluObject). (The idl2isl translator automatically adds ilu.CORBA-Object as a SUPERTYPE.) So, if you define an object in ISL, and do not explicitly declare ilu.CORBA-Object as a SUPERTYPE, you will not have the member functions of CORBA::Object available since you do not inherit from it.

Portability and Mapping Variations

The CORBA 2.0 C++ mapping allows for variations in the mapping depending on the C++ compilers support for Name Spaces, Exception Handling, and Run-Time Type information.

The ILU CORBA 2.0 C++ mapping implementation assumes that the C++ compiler supports exceptions. We also assume that the compiler supports RTTI should someone want to do narrowing within the exception hierarchy. [Given that ILU does not provide a Dynamic Invocation Interface, there's no real need to narrow exceptions anyway.]

During the configuration phase of ILU installation (or for Windows, per the definitions in `ILUSRC/runtime/kernel/iluwin.h') a determination is made as to whether or not to use namespaces, nested classes or underscores for IDL modules, based on the C++ compiler in use. [This can be overridden with the configuration option --with-cplusplus-mapping= switch to config.] This results in a C++ runtime that is constructed with one of these approaches in mind. Should a user decide to use a different mapping, this can be done by setting appropriate switches to the stubber, but you must bear in mind that the C++ runtime needs to be in correspondence, since the selection radically changes the names seen by a linker. Based on our knowledge (as of the date of this writing), of the degree of support/bugs for namespaces and nested classes, the following describes the IDL module mapping based on compiler:

C++ Compiler Module Mapping


     Compiler                 Mapping
     ---------------------------------------
     Microsoft Visual C++     underscores
     SunPro                   nested classes
     Gnu                      nested classes

To portably reference things in a interface when the stubber is directed to produce portable code, the stubber generates two macros, one for referring to things from outside the namespace (e.g. when defining a member function), and another for inside the namespace (e.g. inside a class declaration). The names of these macros are the interface name, and the interface name with a '_' (underscore) suffix. These macros expand to some other macros that are defined in the cppportability.hpp file.

To refer to things in the CORBA interface, one uses the CORBA macro. For example, CORBA(Boolean) b_my_result = ILUCPP_TRUE;

Because of possible variations in compiler support for Booleans, CORBA(Boolean) is defined as ILUCPP_BOOL, where ILUCPP_BOOL is defined as either an int (with ILUCPP_TRUE and ILUCPP_FALSE #defined as 1 and 0), or as a bool (with ILUCPP_TRUE and ILUCPP_FALSE #defined as true and false).

Concepts

Servers and Ports

In ILU there is a concept of an 'server object'. In the kernel this is the ilu_Server, which in the C++ runtime is encapsulated asn an iluServer object. This 'server' effectively forms a 'scope' in which true objects reside. This is why for example, and object lookup requires both the 'server' ID, and the object's instance handle - both are needed to uniquely denote an object.

Now a server has some number of 'ports'. A port is basically a means of communicating with the objects inside a server, using a particular combination of protocol and transport. For example, when create an iluServer, the constructor for iluServer automatically adds a port for the communication protocol and transport specified as constructor arguments. We can call iluServer::iluAddPort to have additional ports added. For example we may want to be able to communicate with the objects using sunrpc over tcp/ip, as well as http over tcp/ip. The iluServer has a notion of a default port. This is initially one as specified during construction, but this can be changed if when calling iluServer::iluAddPort we specify that this should become the default port. The default port is the one used when we ask for contact information for an object - that is, if we get the string binding handle for an object, the contact information in that string will reflect the default server port.

Object Tables

True objects may either be created ahead of time, or on an 'as needed' basis, i.e. when a call comes in involving them. The 'as needed' situation is made possible by 'object tables'. An iluServer may have associated with it (at construction time) an iluObjectTable object. When a call comes involving an object in that iluServer that the ILU doesn't already know about, the iluObjectTable object's iluObjectOfInstanceHandle gets called. It is the job of this function to create and return a new object with that instance handle. How it does this is specific to your application - it may read object state off a disk for example. In any event, one thing this function must do is ensure that when it calls the true objects constructor, that it sets the constructor's b_within_object_table argument to true. (Otherwise, internal locking constraints will be violated). While in the iluObjectOfInstanceHandle function, the associated iluServer's lock is held, and if the resulting object is expected to be of a COLLECTIBLE type, the global kernel mutex "gcmu" is also held. The fact that these locks are held somewhat restricts what an application can do inside this mapping procedure.

Threading

The ILU C++ support may be initialized to run in either threaded or non-threaded mode. In non threaded mode, a call to iluServer::iluRun member function results in a call to ILU's 'mainloop'. The mainloop basically sits waiting for an incoming request. When one comes in, the request is invoked. If the implementation of the invoked method makes a call to some other remote object, the mainloop is recursively entered while awaiting a reply. This allows additional requeste to come in and get serviced, preventing deadlock.

When intialized to run in threaded mode, ILU will run one thread for each incoming connection. Note that there may be multiple connections for a particular port (either from different clients, or from the same client who needed another connection because all the ones it had so far were busy at the time). In the case of a non-concurrent protocol (sunrpc, http, courier), the connection thread receives an incoming request, processes it itself, and then waits for the next request. In the case of a concurrent protocol (csunrpc, iiop), the connnection thread receives an incoming request, spawns a worker thread to carry out the request, and immediately goes back to waiting for more incoming requests.

The ILU C++ provides no special concurrency control for methods in your objects (to do so would be presumptive on our part). The method implementor must put appropriate locking in place if it is possible that multiple threads (or recursive mainloop invocations) might be running 'in' an object simultaneously.

Custom Surrogates

A surrogate is an object that is used to represent a remote object. When a method is invoked on a surrogate, the methods implementation in the surrogate transfers the call to the true object, and returns the result of this call, thus providing location transparency. There are times however when it is useful to have the surrogate's method implementation do more than just forward the call to the true object. An application may want a surrogate method implementation that caches the results of calls (potentially reducing network overhead), perform transformations on arguments, output diagnostic information, or whatever.

To facilitate this, the ILU C++ support allows an implementation to supply a function that is called when a surrogate for a particular object type is needed. The function iluCppRuntime::iluSetSurrogateCreator tells the C++ runtime what function to call when a surrogate for an object of the specified class is needed. This allows an implementation to subclass off a surrogate class, and write a new surrogate creation function that creates an instance of this new subclass. Call iluCppRuntime::iluSetSurrogateCreator after you've performed initialization, but before you do any operations which might create a surrogate of the specified class. It basically overwrites the default surrogate creation function set up by the surrogate stubs. It returns the old surrogate creator function, or NULL if was previously no surrogate creator for that class.

A surrogate creator function should at the minimum create an instance of a surrogate, call the instances member function iluAssociateKernelObject passing the iluKernelObject, and then return a pointer to the new instance.

String Binding Handle Manipulation

A String Binding Handle is a textual representation of an object reference. It contains the object's server id, instance id, information about how to contact the object, as well as other information. ILU C++ provides the functions iluCppRuntime::iluFormSBH, iluCppRuntime::iluFormSBHUsingContactInfo, and iluCppRuntime::iluParseSBH for constructing and parsing string binding handles. An object may be obtained from a string binding handle using iluObject::iluStringToObject and the string bindign handle of an object may be obtained by calling the iluObjectToString member function.

Simple Binding

When creating a service, there needs to be some way for clients to find out about the service. ILU C++ provides a simple mechanism to achieve this. Objects may be published, looked up, and their publications withdrawn using the appropriate member functions (iluPublish, iluLookup, iluWithdraw).

Object Activation

An true object is initially 'Active', which means that its ISL (or IDL as the case may be) defined methods may be invoked on it from outside its process (or from another language within that same process). An object may be made unavailable to outside calls, i.e. marked 'inactive' by calling its iluDeactivate member function. It may may be reactivated by calling its iluActivate member function.

An object is initially available from the outside until it is deactivated Objects that are involved in a call (i.e. sent or received as arguments, or the object the method is being invoked on) need to be protected from deletion for the duration of that involvement (for example, you don't want some thread deleting a true object when it's currently the target of a method call). The C++ runtime keeps track of what objects are involved in a call, and will attempt to prevent them from being deleted until the call is completed.

The application programmer needs to assist in this by calling, in the most specific destructor, iluDeactivate (inherited virtually from iluObject). iluDeactivate blocks any further incoming calls involving the object, and wait for any ongoing calls using the object to complete. Next the destructor should perform any object specific cleanup. Finally, the destructor in iluObject will break the association between the kernel object and this object, allowing the kernel object to be potentially freed.

Security

A client may set the Passport to be used on outgoing calls by creating and setting up an iluPassport, and then passing the passport in a call to iluPassport::iluSetPassport. This sets the passport to be used in the thread that made the call - i.e. iluPassport are on a per thread basis. Note that before your thread exits, you should either call iluSetPassport(NULL), or delete the iluPassport in use (assuming it's only in use for a single thread). The iluPassport (if any) currently setup for a thread can be retrieved by calling iluPassport::iluGetPassport.

A Server may obtain the iluPassport of the caller (if any) of a method by using the iluPassport::iluGetCallerPassport() function.

A iluServer may be constructed to use a particular identity by specifying a iluPassport as a constructor argument. This identity is used to identify the principal offering the service.

Static Initialization

The C++ Runtime normally relies on the static initializers in the files that the stubber generates to place initialization functions onto internal lists so that they will be invoked when the application calls iluCppRuntime::Initialize. However, it is not guaranteed by the ANSI C++ that static initializers are called upon the loading of a compilation unit. We have only had a report of one compiler that did not run the static initializers at load time (in fact, it was reported that it did not run them ever! - bug!?). We have observed static initialization at load time in Visual C++, SunPro and GNU compilers. In the event that you end up using a compiler that does not call the static initializers at load time, you can use the stubber defined initialization macros that are generated in the common header file for each interface.

(It should be pointed out that the CORBA 2.0 C++ Runtime does not suffer from the static initializer issues that plagued ILU's original C++ support. No ILU calls are actually made until iluCppRuntime::iluInitialize is called, allowing one to set up different mainloops, etc.)

Building an Application

Running the Stubber

To generate CORBA 2.0 C++ stubs from an ISL file, use the program cpp2-stubber. The stubber has the following usage:


     Usage: cpp2-stubber [arguments] Islfile [ISLFILE ...]
		 [arguments] can be any of the following:
		 [-nu|-underscores]
		 [-np|-portable]
		 [-nn|-nested]
		 [-ns|-namespaces]

The switches can be used to direct the stubber to produce code that using a specific module mapping, or portable module mapping. The default is whatever is found appropriate during the configuration phase of ILU installation (see "Portability and Mapping Variations"). Note that generating a specific (non-portable) mapping that does not match the platform default, is likely to cause errors at link time due to naming differences.

Stubber Generated Files

For an interface Foo the stubber generates:

`Foo-cpp.hpp' which contains the classes for the abstract object hierarchy, as well as any other declarations needed by both client and server.

`Foo-cpp.cpp', which contains any definitions needed by both client and server, which contains A has no supertypes, the A class 'public virtual' inherits from the iluObject class. An object described in IDL will implicity inherit from CORBA::Object (which in turn inherits from iluObject). (The idl2isl translator automatically adds ilu.CORBA-Object as a SUPERTYPE.) So, if you define an object in ISL, and do not explicitly declare ilu.CORBA-Object as a SUPERTYPE, you will not have the member functions of CORBA::Object available since you do not inherit from it.

Portability and Mapping Variations

The CORBA 2.0 C++ mapping allows for variations in the mapping depending on the C++ compilers support for Name Spaces, Exception Handling, and Run-Time Type information.

The ILU CORBA 2.0 C++ mapping implementation assumes that the C++ compiler supports exceptions. We also assume that the compiler supports RTTI should someone want to do narrowing within the exception hierarchy. [Given that ILU does not provide a Dynamic Invocation Interface, there's no real need to narrow exceptions anyway.]

During the configuration phase of ILU installation (or for Windows, per the definitions in `ILUSRC/runtime/kernel/iluwin.h') a determination is made as to whether or not to use namespaces, nested classes or underscores for IDL modules, based on the C++ compiler in use. [This can be overridden with the configuration option --with-cplusplus-mapping= switch to config.] This results in a C++ runtime that is constructed with one of these approaches in mind. Should a user decide to use a different mapping, this can be done by setting appropriate switches to the stubber, but you must bear in mind that the C++ runtime needs to be in correspondence, since the selection radically changes the names seen by a linker. Based on our knowledge (as of the date of this writing), of the degree of support/bugs for namespaces and nested classes, the following describes the IDL module mapping based on compiler:

C++ Compiler Module Mapping


     Compiler                 Mapping
     ---------------------------------------
     Microsoft Visual C++     underscores
     SunPro                   nested classes
     Gnu                      nested classes

To portably reference things in a interface when the stubber is directed to produce portable code, the stubber generates two macros, one for referring to things from outside the namespace (e.g. when defining a member function), and another for inside the namespace (e.g. inside a class declaration). The names of these macros are the interface name, and the interface name with a '_' (underscore) suffix. These macros expand to some other macros that are defined in the cppportability.hpp file.

To refer to things in the CORBA interface, one uses the CORBA macro. For example, CORBA(Boolean) b_my_result = ILUCPP_TRUE;

Because of possible variations in compiler support for Booleans, CORBA(Boolean) is defined as ILUCPP_BOOL, where ILUCPP_BOOL is defined as either an int (with ILUCPP_TRUE and ILUCPP_FALSE #defined as 1 and 0), or as a bool (with ILUCPP_TRUE and ILUCPP_FALSE #defined as true and false).

Concepts

Servers and Ports

In ILU there is a concept of an 'server object'. In the kernel this is the ilu_Server, which in the C++ runtime is encapsulated asn an iluServer object. This 'server' effectively forms a 'scope' in which true objects reside. This is why for example, and object lookup requires both the 'server' ID, and the object's instance handle - both are needed to uniquely denote an object.

Now a server has some number of 'ports'. A port is basically a means of communicating with the objects inside a server, using a particular combination of protocol and transport. For example, when create an iluServer, the constructor for iluServer automatically adds a port for the communication protocol and transport specified as constructor arguments. We can call iluServer::iluAddPort to have additional ports added. For example we may want to be able to communicate with the objects using sunrpc over tcp/ip, as well as http over tcp/ip. The iluServer has a notion of a default port. This is initially one as specified during construction, but this can be changed if when calling iluServer::iluAddPort we specify that this should become the default port. The default port is the one used when we ask for contact information for an object - that is, if we get the string binding handle for an object, the contact information in that string will reflect the default server port.

Object Tables

True objects may either be created ahead of time, or on an 'as needed' basis, i.e. when a call comes in involving them. The 'as needed' situation is made possible by 'object tables'. An iluServer may have associated with it (at construction time) an iluObjectTable object. When a call comes involving an object in that iluServer that the ILU doesn't already know about, the iluObjectTable object's iluObjectOfInstanceHandle gets called. It is the job of this function to create and return a new object with that instance handle. How it does this is specific to your application - it may read object state off a disk for example. In any event, one thing this function must do is ensure that when it calls the true objects constructor, that it sets the constructor's b_within_object_table argument to true. (Otherwise, internal locking constraints will be violated). While in the iluObjectOfInstanceHandle function, the associated iluServer's lock is held, and if the resulting object is expected to be of a COLLECTIBLE type, the global kernel mutex "gcmu" is also held. The fact that these locks are held somewhat restricts what an application can do inside this mapping procedure.

Threading

The ILU C++ support may be initialized to run in either threaded or non-threaded mode. In non threaded mode, a call to iluServer::iluRun member function results in a call to ILU's 'mainloop'. The mainloop basically sits waiting for an incoming request. When one comes in, the request is invoked. If the implementation of the invoked method makes a call to some other remote object, the mainloop is recursively entered while awaiting a reply. This allows additional requeste to come in and get serviced, preventing deadlock.

When intialized to run in threaded mode, ILU will run one thread for each incoming connection. Note that there may be multiple connections for a particular port (either from different clients, or from the same client who needed another connection because all the ones it had so far were busy at the time). In the case of a non-concurrent protocol (sunrpc, http, courier), the connection thread receives an incoming request, processes it itself, and then waits for the next request. In the case of a concurrent protocol (csunrpc, iiop), the connnection thread receives an incoming request, spawns a worker thread to carry out the request, and immediately goes back to waiting for more incoming requests.

The ILU C++ provides no special concurrency control for methods in your objects (to do so would be presumptive on our part). The method implementor must put appropriate locking in place if it is possible that multiple threads (or recursive mainloop invocations) might be running 'in' an object simultaneously.

Custom Surrogates

A surrogate is an object that is used to represent a remote object. When a method is invoked on a surrogate, the methods implementation in the surrogate transfers the call to the true object, and returns the result of this call, thus providing location transparency. There are times however when it is useful to have the surrogate's method implementation do more than just forward the call to the true object. An application may want a surrogate method implementation that caches the results of calls (potentially reducing network overhead), perform transformations on arguments, output diagnostic information, or whatever.

To facilitate this, the ILU C++ support allows an implementation to supply a function that is called when a surrogate for a particular object type is needed. The function iluCppRuntime::iluSetSurrogateCreator tells the C++ runtime what function to call when a surrogate for an object of the specified class is needed. This allows an implementation to subclass off a surrogate class, and write a new surrogate creation function that creates an instance of this new subclass. Call iluCppRuntime::iluSetSurrogateCreator after you've performed initialization, but before you do any operations which might create a surrogate of the specified class. It basically overwrites the default surrogate creation function set up by the surrogate stubs. It returns the old surrogate creator function, or NULL if was previously no surrogate creator for that class.

A surrogate creator function should at the minimum create an instance of a surrogate, call the instances member function iluAssociateKernelObject passing the iluKernelObject, and then return a pointer to the new instance.

String Binding Handle Manipulation

A String Binding Handle is a textual representation of an object reference. It contains the object's server id, instance id, information about how to contact the object, as well as other information. ILU C++ provides the functions iluCppRuntime::iluFormSBH, iluCppRuntime::iluFormSBHUsingContactInfo, and iluCppRuntime::iluParseSBH for constructing and parsing string binding handles. An object may be obtained from a string binding handle using iluObject::iluStringToObject and the string bindign handle of an object may be obtained by calling the iluObjectToString member function.

Simple Binding

When creating a service, there needs to be some way for clients to find out about the service. ILU C++ provides a simple mechanism to achieve this. Objects may be published, looked up, and their publications withdrawn using the appropriate member functions (iluPublish, iluLookup, iluWithdraw).

Object Activation

An true object is initially 'Active', which means that its ISL (or IDL as the case may be) defined methods may be invoked on it from outside its process (or from another language within that same process). An object may be made unavailable to outside calls, i.e. marked 'inactive' by calling its iluDeactivate member function. It may may be reactivated by calling its iluActivate member function.

An object is initially available from the outside until it is deactivated Objects that are involved in a call (i.e. sent or received as arguments, or the object the method is being invoked on) need to be protected from deletion for the duration of that involvement (for example, you don't want some thread deleting a true object when it's currently the target of a method call). The C++ runtime keeps track of what objects are involved in a call, and will attempt to prevent them from being deleted until the call is completed.

The application programmer needs to assist in this by calling, in the most specific destructor, iluDeactivate (inherited virtually from iluObject). iluDeactivate blocks any further incoming calls involving the object, and wait for any ongoing calls using the object to complete. Next the destructor should perform any object specific cleanup. Finally, the destructor in iluObject will break the association between the kernel object and this object, allowing the kernel object to be potentially freed.

Security

A client may set the Passport to be used on outgoing calls by creating and setting up an iluPassport, and then passing the passport in a call to iluPassport::iluSetPassport. This sets the passport to be used in the thread that made the call - i.e. iluPassport are on a per thread basis. Note that before your thread exits, you should either call iluSetPassport(NULL), or delete the iluPassport in use (assuming it's only in use for a single thread). The iluPassport (if any) currently setup for a thread can be retrieved by calling iluPassport::iluGetPassport.

A Server may obtain the iluPassport of the caller (if any) of a method by using the iluPassport::iluGetCallerPassport() function.

A iluServer may be constructed to use a particular identity by specifying a iluPassport as a constructor argument. This identity is used to identify the principal offering the service.

Static Initialization

The C++ Runtime normally relies on the static initializers in the files that the stubber generates to place initialization functions onto internal lists so that they will be invoked when the application calls iluCppRuntime::Initialize. However, it is not guaranteed by the ANSI C++ that static initializers are called upon the loading of a compilation unit. We have only had a report of one compiler that did not run the static initializers at load time (in fact, it was reported that it did not run them ever! - bug!?). We have observed static initialization at load time in Visual C++, SunPro and GNU compilers. In the event that you end up using a compiler that does not call the static initializers at load time, you can use the stubber defined initialization macros that are generated in the common header file for each interface.

(It should be pointed out that the CORBA 2.0 C++ Runtime does not suffer from the static initializer issues that plagued ILU's original C++ support. No ILU calls are actually made until iluCppRuntime::iluInitialize is called, allowing one to set up different mainloops, etc.)

Building an Application

Running the Stubber

To generate CORBA 2.0 C++ stubs from an ISL file, use the program cpp2-stubber. The stubber has the following usage:


     Usage: cpp2-stubber [arguments] Islfile [ISLFILE ...]
		 [arguments] can be any of the following:
		 [-nu|-underscores]
		 [-np|-portable]
		 [-nn|-nested]
		 [-ns|-namespaces]

The switches can be used to direct the stubber to produce code that using a specific module mapping, or portable module mapping. The default is whatever is found appropriate during the configuration phase of ILU installation (see "Portability and Mapping Variations"). Note that generating a specific (non-portable) mapping that does not match the platform default, is likely to cause errors at link time due to naming differences.

Stubber Generated Files

For an interface Foo the stubber generates:

`Foo-cpp.hpp' which contains the classes for the abstract object hierarchy, as well as any other declarations needed by both client and server.

`Foo-cpp.cpp', which contains any definitions needed by both client and server, which contains A has no supertypes, the A class 'public virtual' inherits from the iluObject class. An object described in IDL will implicity inherit from CORBA::Object (which in turn inherits from iluObject). (The idl2isl translator automatically adds ilu.CORBA-Object as a SUPERTYPE.) So, if you define an object in ISL, and do not explicitly declare ilu.CORBA-Object as a SUPERTYPE, you will not have the member functions of CORBA::Object available since you do not inherit from it.

Portability and Mapping Variations

The CORBA 2.0 C++ mapping allows for variations in the mapping depending on the C++ compilers support for Name Spaces, Exception Handling, and Run-Time Type information.

The ILU CORBA 2.0 C++ mapping implementation assumes that the C++ compiler supports exceptions. We also assume that the compiler supports RTTI should someone want to do narrowing within the exception hierarchy. [Given that ILU does not provide a Dynamic Invocation Interface, there's no real need to narrow exceptions anyway.]

During the configuration phase of ILU installation (or for Windows, per the definitions in `ILUSRC/runtime/kernel/iluwin.h') a determination is made as to whether or not to use namespaces, nested classes or underscores for IDL modules, based on the C++ compiler in use. [This can be overridden with the configuration option --with-cplusplus-mapping= switch to config.] This results in a C++ runtime that is constructed with one of these approaches in mind. Should a user decide to use a different mapping, this can be done by setting appropriate switches to the stubber, but you must bear in mind that the C++ runtime needs to be in correspondence, since the selection radically changes the names seen by a linker. Based on our knowledge (as of the date of this writing), of the degree of support/bugs for namespaces and nested classes, the following describes the IDL module mapping based on compiler:

C++ Compiler Module Mapping


     Compiler                 Mapping
     ---------------------------------------
     Microsoft Visual C++     underscores
     SunPro                   nested classes
     Gnu                      nested classes

To portably reference things in a interface when the stubber is directed to produce portable code, the stubber generates two macros, one for referring to things from outside the namespace (e.g. when defining a member function), and another for inside the namespace (e.g. inside a class declaration). The names of these macros are the interface name, and the interface name with a '_' (underscore) suffix. These macros expand to some other macros that are defined in the cppportability.hpp file.

To refer to things in the CORBA interface, one uses the CORBA macro. For example, CORBA(Boolean) b_my_result = ILUCPP_TRUE;

Because of possible variations in compiler support for Booleans, CORBA(Boolean) is defined as ILUCPP_BOOL, where ILUCPP_BOOL is defined as either an int (with ILUCPP_TRUE and ILUCPP_FALSE #defined as 1 and 0), or as a bool (with ILUCPP_TRUE and ILUCPP_FALSE #defined as true and false).

Concepts

Servers and Ports

In ILU there is a concept of an 'server object'. In the kernel this is the ilu_Server, which in the C++ runtime is encapsulated asn an iluServer object. This 'server' effectively forms a 'scope' in which true objects reside. This is why for example, and object lookup requires both the 'server' ID, and the object's instance handle - both are needed to uniquely denote an object.

Now a server has some number of 'ports'. A port is basically a means of communicating with the objects inside a server, using a particular combination of protocol and transport. For example, when create an iluServer, the constructor for iluServer automatically adds a port for the communication protocol and transport specified as constructor arguments. We can call iluServer::iluAddPort to have additional ports added. For example we may want to be able to communicate with the objects using sunrpc over tcp/ip, as well as http over tcp/ip. The iluServer has a notion of a default port. This is initially one as specified during construction, but this can be changed if when calling iluServer::iluAddPort we specify that this should become the default port. The default port is the one used when we ask for contact information for an object - that is, if we get the string binding handle for an object, the contact information in that string will reflect the default server port.

Object Tables

True objects may either be created ahead of time, or on an 'as needed' basis, i.e. when a call comes in involving them. The 'as needed' situation is made possible by 'object tables'. An iluServer may have associated with it (at construction time) an iluObjectTable object. When a call comes involving an object in that iluServer that the ILU doesn't already know about, the iluObjectTable object's iluObjectOfInstanceHandle gets called. It is the job of this function to create and return a new object with that instance handle. How it does this is specific to your application - it may read object state off a disk for example. In any event, one thing this function must do is ensure that when it calls the true objects constructor, that it sets the constructor's b_within_object_table argument to true. (Otherwise, internal locking constraints will be violated). While in the iluObjectOfInstanceHandle function, the associated iluServer's lock is held, and if the resulting object is expected to be of a COLLECTIBLE type, the global kernel mutex "gcmu" is also held. The fact that these locks are held somewhat restricts what an application can do inside this mapping procedure.

Threading

The ILU C++ support may be initialized to run in either threaded or non-threaded mode. In non threaded mode, a call to iluServer::iluRun member function results in a call to ILU's 'mainloop'. The mainloop basically sits waiting for an incoming request. When one comes in, the request is invoked. If the implementation of the invoked method makes a call to some other remote object, the mainloop is recursively entered while awaiting a reply. This allows additional requeste to come in and get serviced, preventing deadlock.

When intialized to run in threaded mode, ILU will run one thread for each incoming connection. Note that there may be multiple connections for a particular port (either from different clients, or from the same client who needed another connection because all the ones it had so far were busy at the time). In the case of a non-concurrent protocol (sunrpc, http, courier), the connection thread receives an incoming request, processes it itself, and then waits for the next request. In the case of a concurrent protocol (csunrpc, iiop), the connnection thread receives an incoming request, spawns a worker thread to carry out the request, and immediately goes back to waiting for more incoming requests.

The ILU C++ provides no special concurrency control for methods in your objects (to do so would be presumptive on our part). The method implementor must put appropriate locking in place if it is possible that multiple threads (or recursive mainloop invocations) might be running 'in' an object simultaneously.

Custom Surrogates

A surrogate is an object that is used to represent a remote object. When a method is invoked on a surrogate, the methods implementation in the surrogate transfers the call to the true object, and returns the result of this call, thus providing location transparency. There are times however when it is useful to have the surrogate's method implementation do more than just forward the call to the true object. An application may want a surrogate method implementation that caches the results of calls (potentially reducing network overhead), perform transformations on arguments, output diagnostic information, or whatever.

To facilitate this, the ILU C++ support allows an implementation to supply a function that is called when a surrogate for a particular object type is needed. The function iluCppRuntime::iluSetSurrogateCreator tells the C++ runtime what function to call when a surrogate for an object of the specified class is needed. This allows an implementation to subclass off a surrogate class, and write a new surrogate creation function that creates an instance of this new subclass. Call iluCppRuntime::iluSetSurrogateCreator after you've performed initialization, but before you do any operations which might create a surrogate of the specified class. It basically overwrites the default surrogate creation function set up by the surrogate stubs. It returns the old surrogate creator function, or NULL if was previously no surrogate creator for that class.

A surrogate creator function should at the minimum create an instance of a surrogate, call the instances member function iluAssociateKernelObject passing the iluKernelObject, and then return a pointer to the new instance.

String Binding Handle Manipulation

A String Binding Handle is a textual representation of an object reference. It contains the object's server id, instance id, information about how to contact the object, as well as other information. ILU C++ provides the functions iluCppRuntime::iluFormSBH, iluCppRuntime::iluFormSBHUsingContactInfo, and iluCppRuntime::iluParseSBH for constructing and parsing string binding handles. An object may be obtained from a string binding handle using iluObject::iluStringToObject and the string bindign handle of an object may be obtained by calling the iluObjectToString member function.

Simple Binding

When creating a service, there needs to be some way for clients to find out about the service. ILU C++ provides a simple mechanism to achieve this. Objects may be published, looked up, and their publications withdrawn using the appropriate member functions (iluPublish, iluLookup, iluWithdraw).

Object Activation

An true object is initially 'Active', which means that its ISL (or IDL as the case may be) defined methods may be invoked on it from outside its process (or from another language within that same process). An object may be made unavailable to outside calls, i.e. marked 'inactive' by calling its iluDeactivate member function. It may may be reactivated by calling its iluActivate member function.

An object is initially available from the outside until it