DSOM uses a proxy object in the client's address space to represent the remote object. As mentioned earlier in this chapter, the proxy object encapsulates the operations necessary to forward and invoke methods on the remote object and return the results. By default, proxy generation is done automatically by the DSOM run time. However, if desired, the programmer can cause a user-supplied proxy class to be loaded instead of letting the run time dynamically generate a default proxy class. User-supplied proxies can be useful in specialized circumstances when local processing or data caching is desired.
To build a user-supplied proxy class, it is necessary to understand a bit about how dynamic proxy classes are constructed by the DSOM run time. The DSOM run time constructs a proxy class by creating an instance of a class that inherits the interface and implementation of SOMDClientProxy, and the interface (but not the implementation) of the target class. The methods in the interface of the target object are all overridden to call the somDispatch method (For more details, see "Object references and proxy objects" in section 6.8.)
Every SOM object contains the somDispatch method, inherited from SOMObject. This method is used to dynamically dispatch a method on an object, and can be overridden with application-specific dispatching mechanisms. In SOMDClientProxy, the somDispatch method is overridden to forward method calls to the corresponding remote target object.
So, in effect, when a method is called on a default proxy object created by the DSOM run time, it redispatches the method to the remote object using DSOM's version of somDispatch.
Below is a simple example of a user-supplied proxy class. In this particular example, the proxy object maintains a local, unshared copy of an attribute ("attribute_long") defined in the remote object ("Foo"), while forwarding method invocations ("method1") on to the remote object. The result is that, when multiple clients are talking to the same remote "Foo" object, each client has a local copy of the attribute but all clients share the "Foo" object's implementation of "method1".
Note: It is important to understand that simply setting the attribute in one client's proxy does not affect the value of the attribute in other proxies. Maintaining consistency of the cached data values, if desired, is the responsibility of the user-supplied proxy class.
Following is the IDL file for the "Foo" class:
// foo.idl #include <somdtype.idl> #include <somobj.idl> interface Foo : SOMObject { string method1(out string a, inout long b, in ReferenceData c); attribute long attribute_long; implementation { releaseorder: method1, _set_attribute_long, _get_attribute_long; dllname="foo.dll"; somDefaultInit: override; }; };
The user-supplied proxy class is created by using multiple inheritance between SOMDClientProxy and the target object (in this case "Foo"). Thus, the IDL file for the user-supplied proxy class "Foo__Proxy" (note the two underscores) is as follows:
// fooproxy.idl #include <somdcprx.idl> #include <foo.idl> interface Foo__Proxy : SOMDClientProxy, Foo { implementation { dllname="fooproxy.dll"; method1: override; }; };
When a dynamic proxy class is created by the DSOM run time, the methods inherited from the target class are automatically overridden to use somDispatch. When you build a user-supplied proxy, you need to do this explicitly. This is why "method1" is overridden in the implementation section of the "fooproxy.idl" file.
The implementation of "method1", which was added to the template produced by the SOM Compiler, simply calls the somDispatch method on "somSelf" Because "Foo__Proxy" has inherited the implementation of SOMDClientProxy, calling somDispatch within "method1" sends the method to the remote "Foo" object.
/* fooproxy.c */ #include <somdtype.h> #include <fooproxy.ih> SOM_Scope string SOMLINK method1(Foo__Proxy somSelf, Environment *ev, string* a, long* b, ReferenceData* c) { string ret_str; somId methodId; /* Foo__ProxyData *somThis = Foo__ProxyGetData(somSelf); */ Foo__ProxyMethodDebug("Foo__Proxy","method1"); /* redispatch method, remotely */ methodId = somIdFromString("method1"); _somDispatch(somSelf, (void**)&ret_str, methodId, somSelf, ev, a, b, c); SOMFree(methodId); return ret_str; }
In summary, to build a user-supplied proxy class:
interface Foo_ _Proxy : SOMDClientProxy, Foo
Putting SOMDClientProxy first ensures that its version of somDispatch will be used to dispatch remote method calls.
In the implementation section of the .idl file, override all methods that are to be invoked on the target class. Do not override methods that are to be invoked on the local proxy.