Externalizing a reference to an object for which object wrappers have been installed, using the VisiBroker ORB Object's
object_to_string method, will not propagate those wrappers to the recipient of the stringified reference if the recipient is a different process.
VisiBroker offers two kinds of object wrappers: typed and
untyped. You can mix the use of both of these object wrappers within a single application. For information on typed wrappers, see
“Typed object wrappers”. For information on untyped wrappers, see
“Untyped object wrappers”. The following table summarizes the important distinctions between these two kinds of object wrappers.
Whenever you plan to use typed or untyped object wrappers, you must ensure that you use the -obj_wrapper option with the
idl2cpp compiler when you generate the code for your applications. This will result in the generation of an Object wrapper base class for each of your interfaces.
The following figure shows how an untyped object wrapper's pre_method is invoked before the client stub method and how the
post_method is invoked afterward. It also shows the calling sequence on the server-side with respect to the object implementation.
When a client invokes a method on a bound object, each untyped object wrapper pre_method will receive control before the client's stub routine is invoked. When a server receives an operation request, each untyped object wrapper
pre_method will be invoked before the object implementation receives control. In both cases, the first
pre_method to receive control will be the one belonging to the object wrapper that was
registered first.
When a server's object implementation completes its processing, each post_method will be invoked before the reply is sent to the client. When a client receives a reply to an operation request, each
post_method will be invoked before control is returned to the client. In both cases, the first
post_method to receive control will be the one belonging to the object wrapper that was
registered last.
The TimeWrap.h file, part of the
ObjectWrappers sample applications, illustrates how to define an untyped object wrapper factory that is derived from the
VISObjectWrapper::UntypedObjectWrapperFactory.
Your factory's create method will be invoked to create an untyped object wrapper whenever a client binds to an object or a server invokes a method on an object implementation. The
create method receives the target object, which allows you to design your factory to not create an untyped object wrapper for those object types you wish to ignore. It also receives an enum specifying whether the object wrapper created is for the server side object implementation or the client side object.
The following code sample shows the TimingObjectWrapperFactory, which is used to create an untyped object wrapper that displays timing information for method calls. Notice the addition of the
key parameter to the
TimingObjectWrapperFactory constructor. This parameter is also used by the service initializer to identify the wrapper.
class TimingObjectWrapperFactory
: public VISObjectWrapper::UntypedObjectWrapperFactory
{
public:
TimingObjectWrapperFactory(VISObjectWrapper::Location loc,
const char* key)
: VISObjectWrapper::UntypedObjectWrapperFactory(loc),
_key(key) {}
// ObjectWrapperFactory operations
VISObjectWrapper::UntypedObjectWrapper_ptr
create(
CORBA::Object_ptr target,
VISObjectWrapper::Location loc) {
if (_owrap == NULL) {
_owrap =
new TimingObjectWrapper(_key);
}
return VISObjectWrapper::UntypedObjectWrapper::_duplicate(_owrap);
}
private:
CORBA::String_var _key;
VISObjectWrapper::UntypedObjectWrapper_var _owrap;
};
The following code sample shows the implementation of the TimingObjectWrapper, also defined in the
TimeWrap.h file. Your untyped wrapper must be derived from the
VISObjectWrapper::UntypedObjectWrapper class, and you may provide an implementation for both the
pre_method or
post_method methods in your untyped object wrapper.
Once your factory has been installed, either automatically by the factory's constructor or manually by invoking the VISObjectWrapper::ChainUntypedObjectWrapper::add method. An untyped object wrapper object will be created automatically whenever your client binds to an object or when your server invokes a method on an object implementation.
The pre_method shown in the following code sample invokes the
TimerBegin method, defined in
TimeWrap.C, which uses the
Closure object to save the current time. Similarly, the
post_method invokes the
TimerDelta method to determine how much time has elapsed since the
pre_method was called and print the elapsed time.
Both the pre_method and
post_method receive the parameters shown in the following table.
|
|
|
|
|
|
|
|
|
post_method only parameter used to inform the user of any exceptions that might have occurred during the previous steps of the method invocation.
|
The following code sample shows a portion of the sample file UntypedClient.C which shows the creation, with automatic registration, of two untyped object wrapper factories for a client. The factories are created after the VisiBroker ORB has been initialized, but before the client binds to any objects.
int main(int argc, char* const* argv) {
try {
// Initialize the ORB.
CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);
// Install untyped object wrappers
TimingObjectWrapperFactory timingfact(VISObjectWrapper::Client,
"timeclient");
TraceObjectWrapperFactory tracingfact(VISObjectWrapper::Client,
"traceclient");
// Now locate an account manager.
. . .]
The following code sample illustrates the sample file UntypedServer.C, which shows the creation and registration of untyped object wrapper factories for a server. The factories are created after the VisiBroker ORB is initialized, but before any object implementations are created.
The VISObjectWrapper::ChainUntypedObjectWrapperFactory class
remove method can be used to remove an untyped object wrapper factory from a client or server application. You must specify a location when removing a factory. This means that if you have added a factory with a location of
VISObjectWrapper::Both, you can selectively remove it from the
Client location, the
Server location, or
Both.
On the client side, the first object wrapper registered is client_wrapper_1, so its methods will be the first to receive control. After performing its processing, the
client_wrapper_1 method may pass control to the next object's method in the chain or it may return control to the client.
On the server side, the first object wrapper registered is server_wrapper_1, so its methods will be the first to receive control. After performing its processing, the
server_wrapper_1 method may pass control to the next object's method in the chain or it may return control to the servant.
You derive typed object wrappers from the <interface_name>ObjectWrapper class that is generated by the
idl2cpp compiler.
Notice that this class is derived from the AccountObjectWrapper interface and provides a simple caching implementation of the
balance method, which provides these processing steps:
1
|
Check the _inited flag to see if this method has been invoked before.
|
2
|
If this is the first invocation, the balance method on the next object in the chain is invoked and the result is saved to _balance, the _inited flag is set to true, and the value is returned.
|
class CachingAccountObjectWrapper : public Bank::
AccountObjectWrapper {
public:
CachingAccountObjectWrapper() : _inited((CORBA::Boolean)0) {}
CORBA::Float
balance() {
cout << "+ CachingAccountObjectWrapper: Before Calling Balance" << endl;
if (! _inited) {
_balance = Bank::AccountObjectWrapper::balance();
_inited = 1;
} else {
cout << "+ CachingAccountObjectWrapper: Returning Cached Value" <<
endl;
}
cout << "+ CachingAccountObjectWrapper: After Calling Balance" << endl;
return _balance;
}
. . .
};
A typed object wrapper is registered on the client-side by invoking the <interface_name>::add method that is generated for the class by the
idl2cpp compiler. Client-side object wrappers must be registered after the
ORB_init method has been called, but before any objects are bound. The following code sample shows a portion of the
TypedClient.java file that creates and registers a typed object wrapper.
. . .
int main(int argc, char* const* argv) {
try {
// Initialize the ORB.
CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);
// Install Typed Object Wrappers for Account.
Bank::AccountObjectWrapper::add(orb,
CachingAccountObjectWrapper::factory,
VISObjectWrapper::Client);
// Get the Manager ID.
PortableServer::ObjectId_var managerId =
PortableServer::string_to_ObjectId("BankManager");
// Locate an Account Manager.
Bank::AccountManager_var manager =
Bank::AccountManager::_bind("/bank_ow_poa", managerId);
. . .
The VisiBroker ORB keeps track of any object wrappers that have been registered for it on the client side. When a client invokes the _bind method to bind to an object of that type, the necessary object wrappers will be created. If a client binds to more than one instance of a particular class of object, each instance will have its own set of wrappers.
As with a client application, a typed object wrapper is registered on the server side by invoking the <interface_name>::add method. Server side, typed object wrappers must be registered after the
ORB_init method has been called, but before an object implementation services a request. The following code sample shows a portion of the
TypedServer.C file that installs a typed object wrapper.
The <interface_name>ObjectWrapper::remove method that is generated for a class by the
idl2cpp compiler allows you to remove a typed object wrapper from a client or server application. You must specify a location when removing a factory. This means that if you have added a factory with a location of
VISObjectWrapper::Both, you can selectively remove it from the
Client location, the
Server location, or
Both.
If you choose to use both typed and untyped object wrappers in your application, all pre_method methods defined for the untyped wrappers will be invoked prior to any typed object wrapper methods defined for an object. Upon return, all typed object wrapper methods defined for the object will be invoked prior to any
post_method methods defined for the untyped wrappers.
The sample applications Client.C and
Server.C make use of a sophisticated design that allows you to use command-line properties to specify which, if any, typed and untyped object wrappers are to be used.
The typed wrappers are created in the BankInit::update initializer, defined in
objectWrappers/BankWrap.C. This initializer will be invoked when the
ORB_init method is invoked and will handle the installation of various typed object wrappers, based on the command-line properties you specify.
The following code sample shows how the initializer uses a set of PropStruct objects to track the command-line options that have been specified and then add or remove
AccountObjectWrapper objects for the appropriate locations.
. . .
static const CORBA::ULong kNumTypedAccountProps = 2;
static PropStruct TypedAccountProps[kNumTypedAccountProps] =
{ { "
BANKaccountCacheClnt", CachingAccountObjectWrapper::factory,
VISObjectWrapper::Client },
{ "
BANKaccountCacheSrvr", CachingAccountObjectWrapper::factory,
VISObjectWrapper::Server }
};
static const CORBA::ULong kNumTypedAccountManagerProps = 4;
static PropStruct
TypedAccountManagerProps[kNumTypedAccountManagerProps] =
{ { "
BANKmanagerCacheClnt", CachingAccountManagerObjectWrapper::factory,
VISObjectWrapper::Client },
{ "
BANKmanagerSecurityClnt", SecureAccountManagerObjectWrapper::factory,
VISObjectWrapper::Client },
{ "
BANKmanagerCacheSrvr", CachingAccountManagerObjectWrapper::factory,
VISObjectWrapper::Server },
{ "
BANKmanagerSecuritySrvr", SecureAccountManagerObjectWrapper::factory,
VISObjectWrapper::Server },
};
void
BankInit::update(int& argc, char* const* argv) {
if (argc > 0) {
init(argc, argv, "-BANK");
CORBA::ULong i;
for (i=0; i < kNumTypedAccountProps; i++) {
CORBA::String_var arg(getArgValue(
TypedAccountProps[i].propname));
if (arg && strlen(arg) > 0) {
if (atoi((char*) arg)) {
Bank::AccountObjectWrapper::add(_orb,
TypedAccountProps[i].fact,
TypedAccountProps[i].loc);
} else {
Bank::AccountObjectWrapper::remove(_orb,
TypedAccountProps[i]Fact,
TypedAccountProps[i].loc);
}
}
}
for (i=0; i < kNumTypedAccountManagerProps; i++) {
CORBA::String_var arg(
getArgValue(
TypedAccountManagerProps[i].propname));
if (arg && strlen(arg) > 0) {
if (atoi((char*) arg)) {
Bank::AccountManagerObjectWrapper::add(_orb,
TypedAccountManagerProps[i]Fact,
TypedAccountManagerProps[i].loc);
} else {
Bank::AccountManagerObjectWrapper::remove(_orb,
TypedAccountManagerProps[i]Fact,
TypedAccountManagerProps[i].loc);
}
}
}
}
}
The untyped wrappers are created and registered in the TraceWrapInit::update and
TimingWrapInit::update methods, defined in
BankWrappers/TraceWrap.C and
TimeWrap.C. These initializers will be invoked when the
ORB_init method is invoked and will handle the installation of various untyped object wrappers.
The following code sample shows a portion of the TraceWrap.C file, which will install the appropriate untyped object wrapper factories, based on the command-line properties you specify.
TraceWrapInit::update(int& argc, char* const* argv) {
if (argc > 0) {
init(argc, argv, "-TRACEWRAP");
VISObjectWrapper::Location loc;
const char* propname;
LIST(VISObjectWrapper::UntypedObjectWrapperFactory_ptr) *list;
for (CORBA::ULong i=0; i < 3; i++) {
switch (i) {
case 0:
loc = VISObjectWrapper::Client;
propname = "TRACEWRAPclient";
list = &_clientfacts;
break;
case 1:
loc = VISObjectWrapper::Server;
propname = "TRACEWRAPserver";
list = &_serverfacts;
break;
case 2:
loc = VISObjectWrapper::Both;
propname = "TRACEWRAPboth";
list = &_bothfacts;
break;
}
CORBA::String_var getArgValue(property_value(propname));
if (arg && strlen(arg) > 0) {
int numNew = atoi((char*) arg);
char key_buf[256];
for (CORBA::ULong j=0; j < numNew; j++) {
sprintf(key_buf, "%s-%d", propname, list->size());
list->add(new TraceObjectWrapperFactory(loc,
(const char*) key_buf));
}
}
}
}
}