The three components of a Jini system are clients , services, and service locators, each of which can run anywhere on the network. These will be implemented using Java code running in Java Virtual Machines (JVMs). The implementation may be in pure Java but it could make use of native code using JNI (Java Native Interface) or make external calls to other applications. Often, each of these applications will run in its own JVM on its own computer, though they could run on the same machine or even share the same JVM. When they run, they will need access to Java class files, just like any other Java application. Each component will use the CLASSPATH environment variable or use the CLASSPATH option with the runtime to locate the classes it needs to run.
However, Jini also relies heavily on the ability to move objects across the network, from one JVM to another. In order to do this, particular implementations must make use of support services such as RMI daemons and HTTP (or other) servers. The particular support services required depend on implementation details, and so may vary from one Jini component to another.
A Java object running as a service has a proxy component exported to the service locators and then onto a client. The proxy passes through a service locator's JVM in "passive" form and is activated (brought to life) in the client's JVM. Essentially, a snapshot of the object's state is taken using serialization, and this snapshot is moved around.
An object consists of both code and data, and it cannot be reconstituted from just its data ”the code is also required. So, where is the code? This is where a distributed Jini application differs from a standalone application or a client-server application: the code is not likely to be on the client side. If it was required to be on the client side, then Jini would lose almost all of its flexibility because it wouldn't be possible to just add new devices and their code to a network. The class definitions are most likely on the server, or perhaps on the vendor's home Web site.
This means that class definitions for service proxy objects must also be downloaded, usually from where the service came from. This could be done using a variety of methods , but most commonly an HTTP or FTP protocol is used. The service specifies the protocol and also the location of the class files using the java.rmi.server. codebase property. The object's serialized data contains this codebase, which is used by the client to access the class files.
If the codebase specifies an HTTP URL, then there must be an HTTP server running at that URL and the class files must be on this server. This often means that there is one HTTP server per service, but this isn't required ”a set of services could make their class files available from a single HTTP server, and this server could be running on a different machine than the services. This gives two sets of class files: the set needed to run the service (specified by CLASSPATH ) and the set needed to reconstitute objects at the client (specified by the codebase property). For example, the mahalo service supplied by Sun as a transaction manager uses the class files in mahalo.jar to run the service and the class files in mahalo-dl.jar to reconstitute the transaction manager proxy at the client. These files and support services are shown in Figure 1-12.
Figure 1-12: Support services for mahalo
To run mahalo , the CLASSPATH must include mahalo.jar , and to reconstitute its proxy on a client, the codebase property must be set to mahalo-dl.jar .
As mentioned earlier, a proxy service gets exported to the client, and in most cases it will need to communicate with its host service. There are many ways to do this, which are discussed in full in later chapters. One mechanism is the Java Remote Method Invocation (RMI) system. This comes in two flavors in JDK 1.2: the original UnicastRemoteObject and the newer Activatable class. Whereas UnicastRemoteObject requires a process to remain alive and running, Activatable objects can be stored in a passive state and the Activation system will create a new JVM if needed when a method call is made on the object. While passive, an activatable object will need to be stored on some server, and this server must be one that can accept method calls and activate the objects. This server is called an RMI daemon , and Sun supplies such a server, called rmid .
This is really obscure and deep stuff if you are new to RMI or even to the changes it is going through. So why is it needed? Sun supplies a service locator called reggie , and this is really just another Jini service that plays a special role. It exports proxy objects ”the registrar objects. What makes this complex is that reggie uses Activatable in its implementation. In order to run reggie , you first have to start an rmid server on the same machine, and then reggie will register with it.
Running rmid has beneficial side-effects. It maintains log files of its own state, which includes the activable objects it is storing. So reggie can crash or terminate, and rmid will restore it as needed. Indeed, even rmid can crash or be terminated , and it will use its log files to restore state so that it can still accept calls for reggie objects.