A client can only communicate with a CORBA object if it possesses a reference to that object. This raises the question of how the client obtains its initial object reference. The fact that some IDL operation may return an object reference is of no help here: without a reference to specify as its target, there is no way to invoke this operation.
In more detail, before a client can enter the CORBA environment, it must first:
CORBA provides a standard set of operations, specified in pseudo IDL (PIDL), to initialize applications and obtain the appropriate object references.
Operations providing access to the ORB reside in the CORBA
module. (Like an IDL interface declaration, a (P)IDL module declaration defines a new namespace for the body of declarations it encloses. What it does not do is define a new type of CORBA object.) Operations providing access to an Object Adapter, Interface Repository, Naming Service, and other Object Services reside in the ORB interface defined within the CORBA
module.
To provide some flavor of PIDL, here is a fragment of the PIDL specification of CORBA that we rely on in our implementation of the bank client.
module CORBA {
interface Object {
boolean is_a (in string logical_type_id);
...
};
interface ORB {
string object_to_string (in Object obj);
Object string_to_object (in string str);
...
};
...
typedef string ORBid;
typedef sequence <string> arg_list;
ORB ORB_init (inout arg_list argv, in ORBid orb_identifier);
};
The Object
interface is implicitly inherited by all IDL interfaces, much as every Common Lisp class inherits from the class standard-object
.
The is_a
operation provides a test for inheritance (the logical_type_id
is a string representation of an interface identifier). The operation returns true if the object is an instance of that interface, including if that interface is an ancestor of the most derived interface of that object.
The ORB operations object_to_string
and string_to_object
provide an invertible mapping from object references to their representations as strings.
Notice that the CORBA operation ORB_init
is defined outside the scope of any interface, providing a means of bootstrapping into the CORBA world. Calling ORB_init
initializes the ORB, returning an ORB pseudo-object that can be used as the target for further ORB operations.
Like most other language bindings, the Common Lisp binding adopts the pseudo-objects approach in which these CORBA and ORB operations are accessed by applying the binding's normal IDL mapping rules to the PIDL specification.
In this tutorial, we use a very simple technique to obtain the initial object reference. The client assumes that the server has published a reference to its implementation of the bank
object, encoded as a string, in a shared file. After starting up, the client reads the file, decodes the string as an object reference, and then uses this reference as the target of further operations.
Here is the remaining Common Lisp code that completes the implementation of the client:
(defun bank-client ()
(let ((orb (op:orb_init nil "LispWorks ORB")))
(let ((bank-ref (op:narrow 'BankingDemo:bank
(file-to-object orb))))
(capi:display (make-instance 'bank-interface
:bank-ref bank-ref
:title "Corba Bank")))))
The defparameter *bank-ior-file*
is the name of the shared file used to pass the reference of the bank
object from the server to the client.
The method file-as-string
reads a file's contents.
The top-level let
statement first initializes The LispWorks ORB by calling the Common Lisp generic function op:ORB_init
corresponding to the PIDL ORB_init
operation. The first argument to this call is an empty list. Passing an empty sequence instructs the op:ORB_init
function to ignore this argument and use the application's command line arguments (if any) instead. The value of the second argument, "LispWorks ORB"
, merely identifies the ORB to use.
Invoking op:string_to_object
on this ORB, passing the string read from the shared file, reconstitutes the string as an unspecific object reference of class CORBA:Object
. Calling the op:narrow
method on this object reference narrows (that is, coerces) it to a more specific object reference of class BankingDemo:bank
. (The op:narrow
method employs an implicit call to the object's is_a
operation to check that the desired coercion is safe.)
Finally, the resulting object reference bank-ref
, of class BankingDemo:bank
, is used to make and start a new bank interface, displaying the initial GUI to the user. The implementation of the client is now complete.