4. Implementing Callbacks
If an application has "callbacks", that is, the server class has the capability of invoking methods
on the client, then the distributed implementation is a bit more complicated than when callbacks are not present.
In particular, when there are callbacks, the client must act as a server as well, and appropriate communication
links must be established for this. In keeping with the philosophy that the migration from a local implementation
to a distributed implementation should be as simple as possible, our goal was to have it so minimal programming
changes are required when creating a distributed implementation of an application that possesses callbacks. Thus,
the idea is that a programmer creates and debugs an application with callbacks and then creates a distributed implementation
by making a small number of code modifications and by creating appropriate wrapper classes (classes that are automatically
generated) .
As with the creation of distributed applications without callbacks, perhaps the best means of revealing the procedure
and requisite programming constructs is through an example. So, consider a two component application of the form
used previously :
However, in this version, Aclass contains a reference to App for callbacks, and one method of the App class
(typically the constructor) calls an Aclass method to set the reference to App. To facilitate the conversion to
a distributed implementation, we require Aclass set the reference to App by implementing the cam.netapp.SetClient
interface.
In the purely local version of the application, the App class constructor has the form
public App() { A = new Aclass(); try{ A.setClient((Object)this); // Using the method defined by // cam.netapp.SetClient to set the } // callback catch(Exception e){}; }
while in the Aclass class, the method setClient(...)
has the form
public void setClient(Object Ob)throws Exception { appClient = (App)Ob; }
The complete codes are contained in the files Sample3/App.java and Sample4/Aclass.java.
Using these constructions gives the Aclass instance the capability of invoking App methods. For demonstration
purposes App contains the methods testCallBack(...)
and printString(...)
. Aclass contains
the method useCallBack(...)
. The construction is tested by having App.main(..)
create
an App instance and invoke the testCallBack(...)
method. This method immediately invokes the Aclass
useCallBack(...)
method which in turn invokes the client instance printString(...)
method.
The output from the App.main(...)
is
The String "Callback Ok" Indicates Success Callback OK
In a distributed implementation, the existence of a callback requires that the App class act as a server class. Thus, wrapper classes AppCI and AppSI are required to implement the connection between Aclass and App. Ultimately, the structure of the distributed application has the form
The additional wrapper classes consist of AppCI and AppSI, classes that enable the Aclass instance access (via
AppCI methods) the methods of the App instance.
To create a distributed implementation from the local implementation consists of
setClient(...)
method
requires modification as well.App.main(...)
. If one doesn't do this, then the AppSI instance remains
after App has exited.
The new App constructor has the form
public App() { // Using local : uncomment the next block // ####################################### // A = new Aclass(); // ####################################### // // Using remote : uncomment the next block // ####################################### A = new AclassCI(); try { A.setVerboseFlag(true);// remove to stop messages .. A.createServerInstance("127.0.0.1",6789); }catch(Exception e) {System.out.println(e.getMessage());} // ####################################### // try{ A.setClient((Object)this); // Using the method defined by // cam.netapp.SetClient } catch(Exception e){System.out.println(e);}; }
while Aclass implementation of cam.netapp.setClient(...) now has the form
public void setClient(Object Ob) throws Exception { appClient = (AppCI)Ob; }
Sample4/App.java and Sample4/Aclass.java
contain the source for the distributed version of the application.
With these changes, when the setClient(...)
method of Aclass is invoked, then the callback structure
described above is automatically instantiated. (This assumes the AppSI is located on the client machine and AppCI
is located on the server machine).
The output from the App.main(...)
with the verbose mode set has the form
NetworkConnection : Setting up Connection NetworkConnection : Connecting to [127.0.0.1] Port : 6789 NetworkConnection : Connected to [127.0.0.1] Start Up Port : 6791 NetworkConnection : Connected to [127.0.0.1] Server Port : 6792 NetworkConnection : Connected to [127.0.0.1] Server Port : 6793 NetworkConnection : Connected to [127.0.0.1] Server Port : 6794 NetworkConnection : Application AclassSI requested NetworkConnection : Remote Class Found NetworkConnection : Remote Class Instantiated NetworkConnection : Streams Connected to Remote Class NetworkConnection : Connection Complete NetworkConnection : Starting Remote Application AclassCI : Connection Complete The String "Callback Ok" Indicates Success Callback OK
So, the steps to the creation of a distributed version of a two component application with callbacks consists of
cam.netapp.SetClient
interface is used by the client class to set the callback reference.