This section discusses how implementations create and register objects with the ORB run time system.
Specifically, the native type PortableServer::Servant
is mapped to the Lisp class named PortableServer:ServantBase
. The native type PortableServer::ServantLocator::Cookie
can take any Lisp value.
An interface corresponding to a class named by a Lisp symbol s with package p and name n may be implemented by extending the class named by the symbol whose package is p and whose name is the concatenation of n to the string "-SERVANT"
.
If the interface has no base interfaces, then the associated skeleton class has as direct superclasses the class corresponding to the class named portableserver:ServantBase
.
Otherwise, if the interface has base interfaces named A, B, C, and so forth, then its associated servant class has as direct superclasses the class corresponding to the servant classes corresponding to A, B, C, and so forth.
Attributes in an interface generate slots of the corresponding name in the OP
package, together with server-side accessor
methods.
The only portable way to implement an operation on a servant class is to use the corba:define-method
macro. The syntax of corba:define-method
is intended to follow the syntax of the Lisp cl:defmethod macro as closely as possible.
The syntax of corba:define-method
is as follows:
corba:define-method function-name {method-qualifier}* lambda-list form* function-name::= {operation-name | (setf operation-name)} operation-name:: symbol method-qualifier::={:before | :after | :around} corba-specialized-lambda-list ::= setf-lambda-list | normal-lambda-list setf-lambda-list ::= (argument-specifier receiver-specifier) normal-lambda-list ::= (receiver-specifier {parameter-specifier}* context-identifier) context-identifier ::= symbol receiver-specifier ::= (receiver-name receiver-class) receiver-name ::= symbol receiver-class ::= symbol parameter-specifier ::= symbol
This corba:define-method
macro is used to implement an operation on an interface. operation-name
is a symbol whose name is the name either of an operation or of an attribute declared in an IDL interface implemented by the class named by the symbol receiver-class
.
The number of parameter-specifiers
listed in the normal-lambda-list
must equal the combined number of in
and inout
parameters declared in the signature of the operation denoted by the function-name
, or 0
if the operation is an attribute. If the function-name
is a list whose car is setf, the corresponding operation-name
should name an attribute that is not readonly.
If function-name denotes an operation, then the effect of corba:define-method
is to inform the ORB that requests for the operation on instances of the class receiver-class
should return the value or values returned by the body forms of the define-method
macro, executed in a new lexical environment in which each parameter-specifier
is bound to the actual parameters and in which the context-identifier
is bound to the value of the corresponding context.
The operation of corba:define-method
in the case in which function-name
names an attribute is analogous. The behavior of auxiliary specifiers and of dispatch is the same as their corresponding action under defmethod. Attribute accessors will be generated automatically and inherited by subclasses of the servant classes; the methods can be overridden by user definitions.
Note that the syntax of corba:define-method
is a strict subset of that of defmethod: every legal corba:define-method
invocation is also a legal defmethod invocation. The main difference between them is that corba:define-method
only allows specialization on the first argument. An implementation is free to extend the syntax of corba:define-method
, for example, to allow type-checking, interlocking, or multiple dispatch.
The first example shows how one might encapsulate a named grid, which is a grid of strings.
This is the IDL of the interface to a named grid of strings:
module example{ interface named_grid{ readonly attribute string name; string get_value ( in unsigned short row, in unsigned short column); void set_value ( in unsigned short row, in unsigned short column, in string value); } }
The IDL compiler might generate a class corresponding to the example::named_grid
interface using code something like this:
(defpackage :example) (defclass example:named_grid(corba:object)())
In order to implement the IDL interface in the previous example, the user would extend the class example:named_grid-servant
.
;; Sample implementation of named_grid (defclass grid-implementation (example:named_grid-servant) ((grid :initarg :grid :initform (make-array '(2 3) :initial-element "Init")))
The attribute in the IDL will cause the class to have a slot op:name
with the appropriate accessors specializing on the class.
The corba:define-method
macro is used to define the methods that implement each of the operations defined in the IDL interface. These implementations do not perform any of the argument or range checking that a production system would, of course, perform.
The implementation is free to define other methods on the class, including print-object methods and auxiliary methods for initialize-instance.
(corba:define-method get_value ((the-grid grid-implementation) row column) (aref (slot-value the-grid 'grid) row column)) (corba:define-method set_value ((the-grid grid-implementation) row column value)) (setf (aref the-grid row column) value))
Developing Component Software with CORBA® - 01 Dec 2021 19:38:37