Dynamic Invocation Interface
|
The Interface Repository
|
The Request Class
|
Creating a DII request
|
Initializing a DII Request
|
Sending a DII Request
|
Dynamic Invocation Interface
The Dynamic Invocation Interface (DII) lets your client applications use any registered object without having to first link the client stubs created for that object by the IDL compiler. With the DII, your client application can dynamically build requests for any object interface that has been stored in the Interface Repository. Object implementations are not required to provide any extra code to handle DII requests.
While client applications that use the DII are not as efficient as applications that use statically-linked client stubs, they offer some important advantages. Clients are not restricted to using just those objects that were defined at the time the client application was compiled. In addition, client applications do not need to be re-compiled in order to access new object implementations.
Steps for Dynamic Invocation
There are five steps that a client follows for dynamic invocation.
Retrieve an object's interface definition from the interface repository.
Repository
and then invoke the methods defined by the Repository
class to locate object implementations. The following table shows the various types of objects that can be contained in the IR. A complete description of this class can be found in the Netscape Internet Service Broker for C++ Reference Guide.
Table 8.1 Objects that can be stored in the IR.
The Repository
Class.
class
CORBA
{
class Repository
: public Container
{
Contained_ptr lookup_id
(const char * search_id);
PrimitiveDef_ptr get_primitive
(PrimitiveKind kind);
StringDef_ptr create_string
(ULong bound);
SequenceDef_ptr create_sequence
(CORBA::ULong bound, IDLType_ptr element_type);
ArrayDef_ptr create_array
(ULong length, IDLType_ptr element_type);
};
...
}; Obtaining an Object's Interface
The library client application could be enhanced to dynamically obtain the Library
interface and obtain information about the add_book
operation.
Dynamically obtaining the Library::add_book
method.
#include <lib_client.hh>
int main(int argc, char *const *argv)
{
CORBA::Boolean ret;
// Initialize the ORB
CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);
// Declare the library object
library_var library_object;
// Declare an interface repository pointer
CORBA::Repository_var rep_object;
try {
// Attempt to bind to the interface repository
rep_object = CORBA::Repository::_bind();
}
// Check for errors
catch(const CORBA::Exception& excep) {
cout << "Error binding to interface repository" << endl;
return(0);
}
// Locate the add_book operation definition. Can the operation be
// located without first locating the interface? CORBA::Contained_var add_req =
try {
rep_object->lookup_id("Library::add_book");
// Bind to the library object.
CORBA::Object_ptr p;
WAIReturnType_t rc;
char* host = "myServer";
int port = 80;
char* uri = "/NameService/libObj";
rc = resolveURI(host, port, uri, p);
// Narrow the reference.
library_object = library::_narrow(p);
}
// Check for errors
catch(const CORBA::Exception& excep) {
cout << "Error binding to library object" << endl;
return(0);
}
// Create a request, initializing the operation name.
Request_var req = library_object->_request(add_req->name());
...
} The Request Class
When your client application invokes a method on an object, a Request
must be created to represent the method invocation. This Request
is written to a buffer and sent to the object implementation. When your client application uses client stubs, this processing occurs transparently. Client applications that use the DII must create and send the Request themselves. The following code listing shows the Request
class.
NOTE: There is no constructor for this class. TheTheObject::_request
method or Object::_create_request methods are used to create aRequest
object, given an object reference.
Request
class.
class CORBA {The
classRequest
{
public:
CORBA::Object_ptrtarget
() const;
const char*operation
() const;
CORBA::NVList_ptrarguments
();
CORBA::NamedValue_ptrresult
();
CORBA::Environment_ptrenv
();
voidctx
(CORBA::Context_ptr ctx);
CORBA::Context_ptrctx
() const;
CORBA::Statusinvoke
();
CORBA::Statussend_oneway
();
CORBA::Statussend_deferred
();
CORBA::Statusget_response
();
CORBA::Statuspoll_response
();
...
};
};
target
is set implicitly from the object reference used to create the Request
. The name of the operation
must be specified when the Request is created. The initialization of the remaining properties is covered in "Initializing a DII Request". A complete description of this class can be found in the Netscape Internet Service Broker for C++ Reference Guide.
Creating a DII request
Once you have obtained the interface to an object, issued a bind to that object and obtained an object reference, you can use one of two methods for creating a Request
object. The following code listing shows the methods offered by the Object
class.
Two methods for creating a Request
object.
class
You can use the CORBA
{
class Object
{
...
Status _create_request
(Context_ptr ctx,
const char * operation,
NVList_ptr arg_list,
NamedValue_ptr result,
Request_ptr request,
Flags req_flags);
Request_ptr _request
(Identifier operation);
...
};
};_create_request
method to create a Request
object, initializing the Context
, the operation
name, the argument list to be passed and the result. The request parameter points to the Request
object that was created for this operation. The req_flags
must be set to OUT_LIST_MEMORY if one or more of the arguments in the arg_list
are output parameters.
You can also use the _request
method to create a Request
object, specifying only the operation name. You must then perform the rest of the initialization manually.
Initializing a DII Request
Initializing a DII request is a two-step process.
Set the context.
Context
object contains a list of properties, stored as NamedValue
objects, that are passed to the object implementation as part of the Request
. These properties represent information that would otherwise be difficult to communicate to the object implementation. A complete description of this class can be found in the Netscape Internet Service Broker for C++ Reference Guide.
The Context
class.
classCORBA
{
classContext
{
public:
const char *context_name
() const;
CORBA::Context_prtparent
();
CORBA::Statuscreate_child
(const char *name,
CORBA::Context_ptr&);
CORBA::Statusset_one_value
(const char *name,
const CORBA::Any&);
CORBA::Statusset_values
(CORBA::NVList_ptr);
CORBA::Statusdelete_values
(const char *name);
CORBA::Statusget_values
(const char *start_scope,
CORBA::Flags,
const char *name,
CORBA::NVList_ptr&) const;
};
Request
are represented with a NVList
object, which stores name-value pairs as NamedValue
objects. You can use the arguments method to obtain a pointer to the arguments. This pointer can then be used to set the names and values of each of the arguments.
classNVList
{
public:
Longcount
() const;
NamedValue_ptradd
(Flags);
NamedValue_ptradd_item
(const char *name, Flags);
NamedValue_ptradd_value
(const char *name, const Any&, Flags);
NamedValue_ptritem
(Long);
Statusremove
(Long);
Statusfree_out_memory
();
};
Any
class. A complete description of this class can be found in the Netscape Internet Service Broker for C++ Reference Guide.
The NamedValue
class.
classNamedValue
{
public:
const char *name
() const;
Any *value
() const;
Flagsflags
() const;
};
Table 8.2 The NamedValue class methods
Table 8.3 TypeCode kinds and their associated parameter lists
The Any Class
This class is used to represent any IDL type so that they may be passed in a type-safe manner. Objects of this class have a pointer to a TypeCode
that defines the object's type and a pointer to the value associated with the object. Methods are provide to construct, copy and destroy an object as well as initialize and query the object's properties. In addition, streaming operators are provided to write the object to a stream. A complete description of this class can be found in the Netscape Internet Service Broker for C++ Reference Guide.
The Any
class.
class
Any
{
public:
Any
();
Any
(const Any&);
Any
(TypeCode_ptr tc, void *value, Boolean release=0);
~Any
();
Any& operator
=(const Any&);
// Overloaded operators for all data types
void operator
<<=(Short);
void operator
<<=(UShort);
void operator
<<=(Long);
void operator
<<=(ULong);
...
TypeCode_ptr type
();
const void *value
() const;
static Any_ptr _nil
();
static Any_ptr _duplicate
(Any *ptr);
static void _release
(Any *ptr);
// Streaming operators to write Anys to stdout, etc.
ostream& operator
<<(ostream&, const Any&);
istream& operator
>>(istream& strm, Any& any);
istream& operator
>>(istream& strm, Any_ptr& any);
...
} The TypeCode Class
This class is used by the Interface Repository and the IDL compiler to represent the type of arguments or attributes.TypeCode objects are also used in the DII to specify an argument's type in conjunction with the Any
class. TypeCode
objects have a kind property and parameter list property. A complete description of this class can be found in the Netscape Internet Service Broker for C++ Reference Guide.
Sending a DII Request
The Request
class provides several methods for sending the request, once it has been properly initialized. The simplest of these is the invoke
method which sends the request and blocks waiting for a response before returning to your client application. The non-blocking method send_deferred
allows your client to send the request and then use the poll_response
method to determine when the response is available. The get_response
method blocks until a response is received.
The send_oneway
method can be used to send a oneway request. Oneway requests do not involve a response being sent from the object implementation.
The result
method returns a pointer to a NamedValue
object that represents the return value.
Example
...
// Assumes that req has been set to Request
// Create TypeCode for structure
CORBA::StructMemberSeq members;
members.length(2);
members[0].name = (const char *)"author";
members[0].type = CORBA::TypeCode::_duplicate(CORBA::_tc_string);
members[1].name = (const char *)"title";
members[1].type = CORBA::TypeCode::_duplicate(CORBA::_tc_string);
bookTypeCode = orb->create_struct_tc("book", "book", members);
// Write out author and title to a MarshalOutBuffer
CORBA::MarshalOutBuffer buf;
buf << argv[1]; // Author
buf << argv[2]; // Title
bookValue.replace(bookTypeCode, buf);
// Get Argument list from request.
CORBA::NVList_var arguments = req->arguments();
arguments->add_value("book", bookValue, CORBA::ARG_IN);
// Set result
// NOTE: All parameters types (IN, OUT, INOUT and RETURN) need
// to be set so that DII knows the data types of all
// arguments.
CORBA::Boolean ret=0;
CORBA::NamedValue_var result(req->result());
CORBA::Any_var resultAny(result->value());
resultAny->replace(CORBA::_tc_boolean, &result);
// Execute the function
req->invoke();
CORBA::Environment_var env = req->env();
if ( env->exception() )
cout << "Exception occured" << endl;
else {
// Get the return value;
ret = *(CORBA::Boolean *)resultAny->value();
}
cout << "Return value from invoke: " << (int)ret << endl;
return(1);
} Sending and Receiving Multiple Requests
A sequence of DII Request
objects can be created using RequestSeq
, defined in the CORBA::ORB
class and shown in the code listing below. A sequence of requests can be sent using the ORB methods send_multiple_requests_oneway
or send_multiple_requests_deferred
. If the sequence of requests is sent as oneway requests, no response is expected from the server to any of the requests.
If the requests in the sequence are sent using send_multiple_requests_deferred
, the poll_next_response
and get_next_response
methods are used to receive the response the server sends for each request.
The ORB method poll_next_response
can be used to determine if a response has been received from the server. This method returns one if one or more responses are available. This method returns zero if there are no responses available.
The ORB method get_next_response
can be used to receive a response. If no response is available, this method will block until a response is received. If you do not wish your client application to block, use the poll_next_response
method to determine when a response is available.
ORB methods for sending multiple requests and receiving the results.
class CORBA {
class ORB {
...
typedef sequence<Request_ptr> RequestSeq;
Status send_multiple_requests_oneway(const RequestSeq &);
Status send_multiple_requests_deferred(const RequestSeq &);
Boolean poll_next_response();
Status get_next_response();
...
};
};
Last Updated: 02/03/98 15:33:56