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 theCORBA 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 theCORBA 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);
};
TheObject interface is implicitly inherited by all IDL interfaces, much as every Common Lisp class inherits from the classstandard-object.
Theis_a operation provides a test for inheritance (thelogical_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 operationsobject_to_string andstring_to_object provide an invertible mapping from object references to their representations as strings.
Notice that the CORBA operationORB_init is defined outside the scope of any interface, providing a means of bootstrapping into the CORBA world. CallingORB_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 thebank 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 "Harlequin Common Lisp 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 thebank object from the server to the client.
The methodfile-as-stringreads a file's contents.
The top-levellet statement first initializes the Harlequin Common Lisp ORB by calling the Common Lisp generic functionop:ORB_init corresponding to the PIDLORB_init operation. The first argument to this call is an empty list. Passing an empty sequence instructs theop:ORB_init function to ignore this argument and use the application's command line arguments (if any) instead. The value of the second argument,"Harlequin Common Lisp ORB", merely identifies the ORB to use.
Invokingop:string_to_object on this ORB, passing the string read from the shared file, reconstitutes the string as an unspecific object reference of classCORBA:Object. Calling theop:narrow method on this object reference narrows (that is, coerces) it to a more specific object reference of classBankingDemo:bank. (Theop:narrow method employs an implicit call to the object'sis_a operation to check that the desired coercion is safe.)
Finally, the resulting object referencebank-ref, of classBankingDemo: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.