Smart Proxies (or Smart Stubs) are basically user-defined proxy classes.
By default, the IDL compiler generates proxy classes for IDL interfaces. The proxy is an exact image of the target object on whom the invocations are to be made by the client, i.e. it has the same methods as the targeting interface. A proxy packadges the request which gets marshalled and sent to the target object.
The user may wish to manually change the proxy code for the following reasons:
1) Cache information about the remote object locally to save the expense of going across the wire for every request.
2) Batch updates/accesses to the remote object.
For instance:
Consider a remote Database which has an API which can update either a
single record or 10 records at one shot. To leverage performance, one
would want to use this method. So a user can use the smart proxy to
implement the 10 record update method by caching single record update
requests.
It is not certain whether this usecase might not induce extra overhead and whether the proxy can be smart enough to deduce the use of this kind of batch processing. Also, this scheme wont work for two-way calls.The "cached-oneways" feature might make more sense in this scenario. Thus the application programmer will have to determine how this caching optimisation changes the semantics of the original interface.
3) The client can make a single request which results in a sequence of invocations to one or possibly more objects.
For instance:
The smart stub has some private methods (since this is user specific
this should be possible) which do validation of the request to be
made. The remote call could result in another call wherein the
validation occurs before it is shoved over the wire.
4) Quality of Service features like load-balancing can be considered by the smart proxy before making the invocation on the appropriate target object.
1) How will the smart proxy be created?
2) Who will create the smart proxy?
3) It has to be done before the invocations on the target object are done, so when will it get created?
4) What about collocation? Will those stubs fall under this category?
5) Will smart proxies work for collocated object references?
A ProxyFactory (either default or user-defined) is needed which will create the stubs (either default or smart). This factory should be able to create different kinds of proxies.
The unchecked_narrow
method needs to return the
appropriate stub.
Collacated stubs need to be handled too. This means that smart proxies need to be generated for collocated object references too.
An existing function for creating stubs has to replaced by a class which will handle all cases viz. default stubs, smart stubs (proxies), collcated stubs.
At a glance:
Classses to be generated by TAO_IDL in addition to the Default Stub:
1. StubFactoryAdaptor
The singleton which has the different stub factories registered with it.
2. DefaultStubFactory
The factory which returns the proxy_ptr which is used in the
unchecked_narow
method to create the appropriate proxy
object.
3. DefaultSmartStub.
The smart stub interface which makes it easier for the
user to simply implement only the methods he wishes to change and also
provides a
common interface to address remote as well as collocated
stubs.
Classes to be defined by the user:
1. SmartFactory - inherits from DefaultStubFactory class.
The factory which will create the smart stub which the user wants. Its necessary that an object of this class is created.
2. SmartStub - derivative of the DefaultSmartStub class.
The stub which has the user desired extra functionality.
*Note: Names are as they are to make it easier to comprehend the concept.
// To be generated by TAO_IDL. class ProxyFactoryAdaptor { // DESCRIPTION: // Behaves like a singleton and contains the // factory object which is used to create the // default/smart Proxys. public: static ProxyFactoryAdaptor *instance (void) { if (ProxyFactoryAdaptor::factory_ == 0) { Perform Double-Checked Locking Optimisation... this->factory = new DefaultFactory; } return this->factory; } // Register the factory with the Adaptor. static register (DefaultFactory *df) { Perform Double-Checked Locking Optimisation... // If there is a factory already existing, replace it. if (ProxyFactoryAdaptor::factory_ != 0) delete this->factory_; this->factory_ = df; } // Remove the factory. static unregister (void) { Perform Double-Checked Locking Optimisation... delete this->factory_; } // Delegation of the Proxy creation to the factory static interface_ptr create_proxy (void) { return this->factory_->create_proxy (); } protected: ProxyFactoryAdaptor (void); static DefaultFactory *factory_; }; // This class will also be generated by TAO_IDL. class DefaultFactory { // DESCRIPTION: // This class is the parent for the different Proxy factories. The // Proxy could either be collocated or remote and hence here only // the Proxy pointer is returned which will be created on invocation of //. public: DefaultFactory (void) { if (this->open () == error) print error; } ~DefaultFactory (void) { this->close (); } // By default the proxy is simply returned. interface_ptr create_proxy (interface_ptr proxy) { return proxy; } // Whenever the factory object is created, automatically it // gets registered with the ProxyFactoryAdaptor. int open (void) { ProxyFactorydaptor::instance ()->register(this); If above fails, return error else 0. } // Job done, unregisteration is done. int close (void) { ProxyFactorydaptor::instance ()->unregister(this); If above fails, return error else 0. } }; // This has to be implemented by the user class SmartFactory : public DefaultFactory { // DESCRIPTION: // An object of this class has to be defined by the user // which will cause it to be registered with the // ProxyFactoryAdaptor. public: Smartinterface_ptr create_proxy (interface_ptr proxy) { return (!CORBA::is_nil (proxy) ? new SmartProxy (proxy) : proxy); } }; // This class will be generated by the TAO_IDL. class DefaultSmartProxy : public virtual DefaultProxy { // DESCRIPTION: // This class is the class from which the user will inherit // and simply override the methods he requires. This extra // level of indirection is necessary to be able to provide // the smartProxy interface for even collcated Proxys. public: DefaultSmartProxy (interface_ptr proxy) : proxy_ (proxy) // Interface operations... int method () { this->proxy_->method (); } ... // @@@ Not sure how to handle support for native exception (i.e., no // CORBA::Environement in the method signatures. Maybe just put it in // the IDL compiler and generate code for pure exception code or not // based on the -Ge option. protected: // This var member denotes the kind of proxy used: // collacated-thru_poa, collocated-direct, or remote. // This is decided by the collocated strategy used along // with the smart Proxys. Note: the collocated Proxys // themselves are smart proxies. The proxy pointer passed // thru the constructor willb eassigned to . The // pointer will actually point to the smart proxy in case // of smart proxies or else to the default proxy. DefaultProxy_var proxy_; }; // This class will be implemented by the user. class VerySmartProxy : public DefaultSmartProxy { // DESCRIPTION: // This is the smart Proxy will is defined by the user // to suit his needs. int method () { print "Yahoo, I am so smart" this->proxy_->method (); } } // Generated by TAO_IDL. Note the changes wherein the // ProxyFactoryAdaptor is used. interface_ptr _unchecked_narrow (CORBA::Object obj, CORBA::Environment &) { if (CORBA::is_nil (obj)) return test::_nil (); TAO_Proxy* Proxy = obj->_stubobj (); stub->_incr_refcnt (); interface_ptr *default_proxy = interface::_nil (); if (obj->_is_collocated () && _TAO_collocation_interface_Stub_Factory_function_pointer != 0) { default_proxy = _TAO_collocation_interface_Stub_Factory_function_pointer (obj); } if (CORBA::is_nil (default_proxy)) ACE_NEW_RETURN (defualt_proxy, interface (stub), test::_nil ()); return ProxyFactoryAdaptor::instance ()->create_proxy (default_proxy); } }
1) Native exceptions? How are these to be handled?
Maybe just put it in the IDL compiler and generate code for pure exception code or not based on the -Ge option.
2) What if the user wants to have a smart proxy which inherits from many interfaces?
First have different smart proxies which inherit from the DefaultSmartProxy (every default smart proxy is for an interface) and then have a new smart proxy inheriting from the previously created smart proxies. But remember: the SmartProxyFactory should create the final smart proxy thru its create_proxy () method.
Nanbor Wang and Dr.Schmidt for their help in designing and discussing this feature.
CORBA Distributed Objects using Orbix - Sean Baker
Visigenic Documentation
Date: 21thSept99