Querying the Registry Launching an Application-Specific Registry

To make this more concrete, consider our remote printer application once again. Suppose we decide on a logical naming convention consisting of the following three components: • Location. A human-readable string describes the location of the printer. • A separator consisting of two colons. • Either the word Color or the words Black and White. This leads to logical names such as: Bobs office::Color Room 445::Black and White Now we can register these printers in a registry, either a global registry or a registry devoted only to remote printers. If we use a global registry, the client will wind up using the reflection API to determine which servers are printers. In the second case, this information is inherent in the fact that the server is registered. In either case, when the end user wants to print a document, the client application can display a list of printers and have the end user select a printer from among the available printers. Lets implement programs that illustrate both of these approaches.

14.4.1 Querying the Registry

RegistryExplorer , defined in the com.ora.rmibook.chapter14.registry package, is a simple application that lists each server in the registry, along with all the interfaces it implements. A screenshot of its user interface is shown in Figur e 14- 1 . Note that this screenshot was taken immediately after running Exam ple 9- 2 . Figure 14-1. The RegistryExplorer user interface The important part of this application is the listener attached to the Check Registry Contents button. The listener calls list to get all the URLs from the registry and then displays the information for each URL in the registry: private class QueryRegistry implements ActionListener { public void actionPerformedActionEvent event { try { String[] names = Naming.listlocalhost:1099; if null==names || 0==names.length { _resultsArea.setTextThe Registry is Empty; return; } _resultsArea.setText; for int counter=0;counternames.length;counter++ { displayInformationForNamenames[counter]; } } catch Exception ignored { } } The displayInformation method takes a single URL, retrieves the stub associated with the URL and then uses reflection to find out which remote interfaces the stub implements: private void displayInformationForNameString name throws Exception { Object value = Naming.lookupname; Collection interfaces = getRemoteInterfacesForObjectvalue; _resultsArea.appendServer named + name + implements the following remote interfaces \n; Iterator i = interfaces.iterator ; while i.hasNext { _resultsArea.append\t + i.next + \n; } return; } private Collection getRemoteInterfacesForObjectObject object { Class objectType = object.getClass ; Class[] interfaces = objectType.getInterfaces ; Class remoteInterface = Remote.class; ArrayList returnValue = new ArrayList ; for int counter=0; counter interfaces.length; counter++ { if remoteInterface.isAssignableFrominterfaces[counter] { returnValue.addinterfaces[counter]; } } return returnValue; }

14.4.2 Launching an Application-Specific Registry

Another approach to the same problem is to simply launch more than one registry. There are two ways to do this: • Using the rmiregistry program supplied with the JDK and specifying a particular port • From within your application via code The first approach is easy; the rmiregistry application takes an integer argument, which is the port that the registry should use. If you omit the port, the default port 1099 is used. Thus, either of the following two command-line invocations produce the same result: rmiregistry rmiregistry 1099 However, you can also specify another port. For example, the following command-line invocation will launch an instance of the RMI registry listening on port 10345: rmiregistry 10345 The second approach, launching a registry from within an application, is only slightly more difficult. You simply use a static method from the LocateRegistry class. Either of the following will create a registry well discuss the second method in more detail in Chapt er 18 : public static Registry createRegistryint port public static Registry createRegistryint port, RMIClientSocketFactory csf, RMIServerSocketFactory ssf The Sun Microsystems, Inc. implementation of the RMI registry uses static variables in order to help solve the bootstrapping problem. These static variables effectively limit you to creating only one registry per JVM. Registering a Registry Within a Registry Given that you can launch a registry from within a JVM using LocateRegistry , and given that the Registry interface extends Remote , its reasonable to wonder whether the created instances of Registry can, themselves, be treated like any other RMI server. The answer is yes. The Naming and LocateRegistry classes are simply bootstrapping conveniences to help you find a running RMI server. However, they dont in any way affect the behavior of the server itself or the behavior of the RMI infrastructure. The following code, for example, creates a registry and binds it into another registry: Registry ourRegistry = LocateRegistry.createRegistryOUR_PORT; Registry preexistingRegistry = LocateRegistry.getRegistry1099; preexistingRegistry.rebindsecondary registry, ourRegistry; This can be very useful; its almost a way to build a directory structure inside the RMI registry. For example, you can imagine defining a central RMI registry, which has only two servers bound into it, using the logical names Printers and BankAccounts. If each of these servers is, itself, an RMI registry, then youve effectively added some hierarchical structure to what was a flat list of servers.

14.5 Limitations of the RMI Registry