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 newly added object implementations.
Repository
and then invoke the methods defined by the Repository
class to locate object implementations. Table 9-1 shows the various types of objects that can be contained in the IR. A complete description of this class can be found in the VisiBroker for
C++ Reference Guide
.Represents the top-level module that contains all other objects in this repository.
Contains a grouping of interfaces. Can also contain constants, typedefs and even other ModuleDef objects.
Contains a list of operations, exceptions, typedefs, constants and attributes that make up an interface.
Defines an attribute associated with an interface.
Defines an operation on an interface. It includes a list of parameters required for this operation and a list of exceptions that may be raised by this operation.
Defines a base interface for named types that are not interfaces.
Defines an exception that may be raised by an operation.
The following example shows 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);
};
...
Library
interface and obtain information about the add_book
operation.
#include <lib_client.hh>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 = rep_object
->lookup_id("Library::add_book");
try {
// Bind to the library object.
library_object = library::bind();
}
// 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());
...
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. Figure 9-1 shows the Request
class.class CORBA {Theclass Request {
public:
CORBA::Object_ptr target() const;
const char* operation() const;
CORBA::NVList_ptr arguments();
CORBA::NamedValue_ptr result();
CORBA::Environment_ptr env();
void ctx(CORBA::Context_ptr ctx);
CORBA::Context_ptr ctx() const;
CORBA::Status invoke();
CORBA::Status send_oneway();
CORBA::Status send_deferred();
CORBA::Status get_response();
CORBA::Status poll_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" and "Initializing Requests from an OperationDef" later in this document. A complete description of this class can be found in the VisiBroker for C++ Reference Guide.Request
object. The following example shows the methods offered by the Object
class.class CORBA {You can use the _create_request method to create aclass 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);
...
};
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.
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 VisiBroker for
C++ Reference Guide
.class CORBA {class Context {
public:
const char *context_name() const;
CORBA::Context_prt parent();
CORBA::Status create_child(const char *name,
CORBA::Context_ptr&);
CORBA::Status set_one_value(const char *name,
const CORBA::Any&);
CORBA::Status set_values(CORBA::NVList_ptr);
CORBA::Status delete_values(const char *name);
CORBA::Status get_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.class NVList {public:
Long count() const;
NamedValue_ptr add(Flags);
NamedValue_ptr add_item(const char *name, Flags);
NamedValue_ptr add_value(const char *name, const Any&, Flags);
NamedValue_ptr item(Long);
Status remove(Long);
Status free_out_memory();
Any
class. A complete description of this class can be found in the VisiBroker for C++ Reference Guide.class NamedValue {The following section lists thepublic:
const char *name() const;
Any *value() const;
Flags flags() const;
NamedValue
class methods. The method is given first followed by the description.Returns a pointer to the name of the item that you can then use to initialize the name.
Returns a pointer to an Any
object representing the item's value that you can then use to initialize the value. For more information, see "The Any Class" on page 9-11.
Indicates if this item in an input argument, an output argument or both an input and output argument. If the item is both an input and output argument, you can specify a flag indicating that the ORB should make a copy of the argument and leave the caller's memory intact. Flags are:
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 VisiBroker for C++ Reference Guide.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);
...
Any
class. TypeCode
objects have a kind property and parameter list property. A complete description of this class can be found in the VisiBroker for
C++ Reference Guide
.struct-name, {member, TypeCode}
union-name, switch TypeCode, {label-value, member-name, TypeCode}
The following section lists TypeCode
constants for IDL data types. The type is given first followed by the name.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.
The following example shows how to send a DII request.
...
// 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);
Request
objects can be created using RequestSeq
, defined in the CORBA::ORB
class and shown in Figure 9-12. 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.
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.
The following example shows 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();
...
};