On inner classes and RMI callbacks Welcome to the first installment of the newest JavaWorld column! Many of you have been asking for a Q&A column for some time, and JavaWorld has heard your call! Welcome to the first installment of Ask the Java Experts, in which Random Walk Computing, New York’s leading Java consulting shop, addresses your questions. To submit a question, e-mail experts@randomwalk.com. While we can’t answer everybody’s submissions, we will try to select a few every month that represent some of your most common questions. Resources for all questions answered in Ask the Java Experts are found at the bottom of the column.Question 1: Is it possible to declare a class inside another class and to have the inner class access the private variable of the main class?Random Walk replies: Certainly! Java 1.1 introduced the concept of inner classes to the Java language. Here’s an example of an inner class accessing a private data member of an enclosing class.public class OuterClass { private static String hiding = "You can't see me!"; public static class InnerClass { public static void showMe() { System.out.println(hiding); } } public static void main (String args[]) { } } When run, this application will print out “You can’t see me!”Question 2: I have a problem with RMI callbacks and hope you will help me out. My server program successfully invokes a client method using callbacks. However since the client method executes on the server side in this case, how I am supposed to manipulate my front end AWT components from this method. Or is it not possible using RMI callbacks. Because I need my front end AWT components such as Lists to get updated with some values when it receives a callback. Please explain.Random Walk replies:We have received quite a few questions regarding RMI this month, from specific issues such as yours to things like “What’s the ding-dong deal with this RMI stuff?”. So we thought we’d use your question as a jumping off point to address RMI as a whole. Here’s the short answer to your question. It’s not correct to say that the client method executes on the server. When using RMI to do callbacks to an application client, the client code does not execute on the application server. Only the RMI proxy or stub class executes on the application’s server machine. The proxy invocation then arranges it so that the implementation class for the callback executes on the VM of the application client. Therefore, since the RMI server logic and the front end AWT components both coexist on the same VM, there’s no problem in having an RMI “callback” update information kept by AWT components.Here’s a much longer answer, with a sample program that illustrates what’s going on:It can be difficult when learning RMI to predict what is going on where. The trick is to remember that for any RMI interface there will be two classes that execute: the proxy or stub class runs in the VM of the caller and the implementation class runs in the VM of the server. The other thing to keep straight is that it can get confusing to label one VM the “client” and the other the “server” for a particular application. In RMI terminology, any VM that initiates an RMI invocation is the “client” and a VM that receives and processes an RMI invocation is the “server.” I find it easier to think of Java VMs as peers, any of which may act as RMI clients or servers depending on the circumstance. Thus, in RMI there is really no such thing as a “callback” — a “callback” is really just an RMI invocation in the other direction! In the context of what many people call “client/server applications,” its helpful to designate the program that performs the user interface functions as the “front end” or “application client” and the program that provides services to that GUI as the “back end” or “application server.”Using this new nomenclature, the question boils down to: Can RMI be used to allow a back-end VM to send update information to a front-end VM, and have the front-end VM use that information to update the information presented by the GUI? Put this way, the answer is: Yes.Enough text. Let’s look at this in code. Suppose we have a front end whose mission in life is to display a list of stock symbols and stock prices that we’re interested in. The job of the back end would then be to notice when a stock’s price changes and update the front end with this information. Upon receiving such an update, the front end then would replace the old price for that stock with the new price in the AWT-based user interface. Since you asked about updating the contents of AWT components using application server-side RMI calls, we’ll use an AWT List component in the GUI. It’s not the prettiest way to do it, but it does keep the code short. Apologies in advance for the flicker; this isn’t a course on AWT programming!RMI in a nutshell Remote Method Invocation (RMI) is a way for Java programs to call other Java programs that execute in other virtual machines, usually across a network.The interface to an RMI server is defined by an interface that extends the java.rmi.Remote interface. All methods defined in remote interfaces must be declared to throw the java.rmi.RemoteException. RMI servers begin by replacing the default SecurityManager with an instance of RMISecurityManager. To advertise available services, an instance of an RMI server object is bound to a name in an RMI registry using the java.rmi.Naming.rebind method. The RMI registry is established by running the rmiregistry daemon.An RMI server implementation must extend the java.rmi.server.UnicastRemoteObject class and must implement the remote interface for the server. Once this class is defined and compiled, then the rmic program is used to automatically generate stub and skeleton classes.RMI clients use the java.rmi.Naming.Lookup method to obtain a reference to RMI server objects. The RMI Interfaces In any well-designed distributed system, it’s the remote interfaces that are the most important parts of the system architecture, so lets start with those. The application server provides an interface called StockInfo. StockInfo defines two method signatures: register and unregister. This is how the front end client tells the StockInfo back-end server that the front end client exists. A registered StockInfo client must implement the StockUpdate interface, and must pass a reference to an object that implements the StockUpdate interface as the sole argument to the register method. Once the StockInfo server has a reference to the StockUpdate object, the StockInfo server implementation may use the reference to talk to the front end client at will. It is this object that acts as the “callback” object in this architecture. Here is the StockInfo interface:package rmistock;import java.rmi.*; public interface StockInfo extends java.rmi.Remote { void register(StockUpdate o) throws RemoteException; void unregister(StockUpdate o) throws RemoteException; } The StockUpdate interface looks like this:package rmistock;import java.rmi.*; public interface StockUpdate extends java.rmi.Remote { void update(String symbol, String price) throws RemoteException; } Once a client has registered with the StockInfo server, the server will periodically invoke the update method of the StockUpdate object. This means that the application client is itself an RMI server, and must be prepared to service RMI invocations anytime after it makes the StockInfo.register call. The StockInfo Server Now that the RMI interfaces are defined, there have to be implementation classes for those interfaces. For the StockInfo interface, that class is called StockInfoImpl. This class has three responsibilities:to implement the StockInfo interfaceto take care of the main line chores of starting an registering an object as a server for the StockInfo interface that well name “rmistock.StockInfo,” andto implement a background thread that obtains stock symbols and prices and notifies each registered client of any change in price for a stock symbol. Implementing the StockInfo interface is very simple: the register method takes the StockUpdate instance passed to it and stores it uniquely in a private Vector. The unregister method deletes the StockUpdate instance from the Vector. Notice that these two methods are synchronized in order to avoid problems that result from the contention of multiple invocations trying to simultaneously access the Vector of StockUpdate instances.Here are the implementations of the StockInfo interface methods:public synchronized void register(StockUpdate o) throws RemoteException { if (!(clients.contains(o))) { clients.addElement(o); System.out.println("Registered new client " + o); } } public synchronized void unregister(StockUpdate o) throws RemoteException { if (clients.removeElement(o)) { System.out.println("Unregistered client " + o); } else { System.out.println("unregister: client " + o + "wasn't registered."); } } The StockInfoImpl server main line code creates an RMI registry on TCP port 5001, instantiates a StockInfoImpl object, registers that object with the RMI registry, and then creates the background stock price update thread and starts it running:public static void main(String args[]) { System.setSecurityManager(new RMISecurityManager()); try { LocateRegistry.createRegistry(5001); StockInfoImpl sii = new StockInfoImpl(); Naming.rebind("//:5001/rmistock.StockInfo", sii); System.out.println("StockInfoImpl registered and ready"); Thread updateThread = new Thread(sii, "StockInfoUpdate"); updateThread.start(); } catch (Exception e) { e.printStackTrace(); } } The price update thread implements a really simple and not particularly realistic simulation of an equities market. It knows about two stocks, IBM and SUN, and simply increments their prices in lock step every second from to 5 in quarter point steps, dropping precipitously back to when the price hits 5.Every time the price changes, the price update thread iterates through the saved Vector of StockUpdate references. It is here that the “callback” is performed via the update method:StockUpdate client = (StockUpdate) e.nextElement(); try { client.update(symbol, "" + price); } catch (RemoteException ex) { try { unregister(client); } catch (RemoteException rex) { } } The code that executes here in the back end’s VM is not the actual implementation of the StockUpdate interface’s update method, but rather a proxy method that serializes the symbol and price Strings back across to the front end VM. On the front end side, those serialized Strings are turned back into Java objects and then passed to the implementation method, which then executes on the front-end’s VM. We’ll see what that implementation actually does when we step through the front end code below.Look at the code in the catch clause: this gets triggered when a front end VM terminates. The update method throws a java.rmi.RemoteException and this catch clause uses that exception as an opportunity to unregister the client so that future iterations of the price update thread don’t bother to try to contact that application client again. The try/catch around the unregister calls is just for form’s sake: unregister is really supposed to be invoked remotely, but here we use it locally and there’s no possibility of a RemoteException being raised.The StockUpdate GUI Client The front end component of this system is implemented in two classes, StockWatcherGUI and StockList.StockWatcherGUI handles the main line code for GUI — it sets up an AWT Frame, and inserts a StockList object into the Frame. It also sets up the front end VM as an RMI server and implementation for the StockUpdate interface. Since the front end always passes a reference to the StockUpdate-implementing object directly to the back end as an argument to the register method, theres no need to register the StockUpdate instance in the RMI registry — no one ever has to look them up. The mainline code, however, does look up the instance reference bound to the rmistock.StockInfo name in the RMI registry for later use.The implementation of the StockUpdate interface is the update method of this StockWatcherGUI class.public synchronized void update(String symbol, String price) throws RemoteException { l.updateStock(symbol, price); // l is an AWT component } Notice again that it is synchronized — even though in this system it is very unlikely that we’ll get more than one update call coming in at once, that’s not guaranteed be the interface definition, and a good RMI server must be ready to operate in a multithreaded environment. This method will execute in the front end’s VM and it has access to the AWT components of the StockWatcherGUI. Once we are in this method, it is child’s play to update the AWT component. In fact, all this method does is to forward the call to our StockList AWT component via the StockList’s updateStock method.The StockList component is a subclass of java.awt.List, so a StockList object is an AWT component. The updateStock method directly modifies the String elements displayed in the list box, formatting them with the incoming stock symbols and prices.public synchronized void updateStock(String symbol, String price) { int i = 0; for (i = 0; i < stocks.length; i++) { if (stocks[i].equals(symbol)) break; } if (i >= stocks.length) return; replaceItem(formatStock(symbol, price), i); } That’s pretty much all there is to it. The complete code, along with build and run scripts for Windows is at javaqa.zip. You have to unpack the zip file, and then run the scripts from the rmi subdirectory. Figure 1 shows a diagram of where each of the objects exist at runtime and how the invocations flow between each of these objects in this RMI-based system.Just to prove to yourself that “callback” code actually executes on the front end, load the .class files on two separate machine. On the machine that will be the back end, delete the StockWatcherGUI.class and StockWatcherGUI_Skel.class files so that the server doesn’t have access to them at all. All it needs is the StockWatcherGUI_Stub.class file — this is the proxy class itself that was generated by rmic.About Random Walk Computing: A Sun Authorized Java CenterTM, Random Walk is the largest Java/CORBA consulting boutique in New York, focusing on solutions for the financial enterprise. Known for their leading edge Java expertise, Random Walk consultants publish and speak about Java in some of the most respected forums in the world. Java