Callback in CORBA Applications

Sometimes, a client should synchronize itself on a change or update that occurs in a server. For example a client, which displays the score of a game, should always get current score stored in a game server. There are two ways a client can do this:

  • Polling: The client can ask the server for the current score periodically.
  • Callback: Request server to send score, only when it changes, to the client.

The primary problem of polling method is that the client may have downloaded the same score possibly many times as the client does not have any idea about when the score changes. Alternatively, instead of downloading the score by the client, the responsibility may be imposed on the server. By doing so, the client gets a score only when it changes, thus reducing the number of messages exchanged. This mechanism is called callback and has a direct positive impact of network bandwidth.

A callback is an operation invocation made by a server to an object that is implemented by a client. To implement this callback mechanism for score application, we write an IDL as follows:

//Callback.idl module Callback {

interface Listener {

void receive(in string s);

};

interface Notifier {

void register(in Listener r);

};

};

In this example, since clients invoke operations on servers and servers invoke operations on clients, IDL defines two interfaces through which each type of application can access the other. Specifically, Listener is implemented at the client side and Notifier is implemented at the server side. A simple implementation (scoreListener.java) of Listener is shown below:

// ScoreListener.java import Callback.*;

class ScoreListener extends ListenerPOA {

public void receive(String s) {

System.out.println(”received: ”+s);

}

}

The received method gets a string (score) and displays it. A sample Notifier implementation (ScoreNotifier.java) is shown below:

// ScoreNotifier.java import Callback.*; import java.util.*;

class ScoreNotifier extends NotifierPOA implements Runnable {

Hashtable Listeners = new Hashtable();

public ScoreNotifier() {

new Thread(this).start();

}

public void register(Listener r) {

System.out.println(”Registered a listener: ”);

Listeners.put(r, r);

}

public void run() {

int score = 0, run;

Random r = new Random();

while(true) {

try {

do {

Thread.sleep(1000+r.nextInt(1000));

}while((run = r.nextInt(7)) == 0);

score += run;

Enumeration e = Listeners.elements();

while(e.hasMoreElements()) {

Listener rec = (Listener)e.nextElement();

System.out.println(”Sent: ”+score);

rec.receive(score+””);

}

}catch(Exception e) {}

}

}

}

The register() method puts the specified Listener in a Hashtable. The listener is created and bound to the ORB by the client. The child thread created from the constructor generates a score artificially and sends it to all the registered Listeners by calling their respective receive() method.

The server (scoreServer.java) merely creates a ScoreNotifier object and exports it to the naming service:

// ScoreServer.java import org.omg.CosNaming.*;

import org.omg.CosNaming.NamingContextPackage.*;

import org.omg.CORBA.*;

import org.omg.PortableServer.*;

public class ScoreServer {

public static void main(String args[]) {

try{

ORB orb = ORB.init(args, null);

POA rootpoa =

POAHelper.narrow(orb.resolve_initial_references(”RootPOA”));

rootpoa.the_POAManager().activate();

ScoreNotifier cal = new ScoreNotifier();

org.omg.CORBA.Object objRef = orb.resolve_initial_references(”NameService”);

NamingContextExt ncRef = NamingContextExtHelper.narrow(objRef);

NameComponent path[] = ncRef.to_name( “ScoreNotifier” );

ncRef.rebind(path, rootpoa.servant_to_reference(cal));

System.out.println(”ScoreServer ready and waiting …”);

orb.run();

} catch (Exception e) {

e.printStackTrace();

}

}

}

The client, on the other hand, gets a reference to the ScoreNotifier object from the name service, creates a ScoreListener object, gets it’s IOR and passes it to the notifier using in its register() method. Remember that the register() method stores this IOR in a Hashtable and is used subsequently to send a score created artificially. The source code (ScoreClient.java) is shown below:

import Callback.*;

import org.omg.CosNaming.*;

import org.omg.CosNaming.NamingContextPackage.*;

import org.omg.CORBA.*;

import org.omg.PortableServer.*;

public class ScoreClient {

public static void main(String args[]) {

try{

ORB orb = ORB.init(args, null);

org.omg.CORBA.Object objRef = orb.resolve_initial_references(”NameService”);

NamingContextExt ncRef = NamingContextExtHelper.narrow(objRef);

Notifier n = NotifierHelper.narrow(ncRef.resolve_str(“ScoreNotifier”));

POA rootpoa =

POAHelper.narrow(orb.resolve_initial_references(”RootPOA”));

rootpoa.the_POAManager().activate();

ScoreListener sl = new ScoreListener();

Listener ref = ListenerHelper.narrow(rootpoa.servant_to_reference(sl));

n.register(ref);

orb.run();

} catch (Exception e) { e.printStackTrace();

}

}

}

Compile and run the application as before. A sample result is shown in Figure 27.3:

Figure 27.3: CORBA Callback mechanism (i) Server (ii) Client

Source: Uttam Kumar Roy (2015), Advanced Java programming, Oxford University Press.

Leave a Reply

Your email address will not be published. Required fields are marked *