Our homes are becoming full of more and more complex pieces of electronic equipment: TVs, microwaves, stereo systems, and so forth - and many of these items have clocks. It's pretty common to find one or more of these clocks flashing; particularly the one on the VCR. Whenever there is a power failure, all the clocks on these pieces of equipment start up again with an incorrect time and signal this by flashing until they are manually corrected. In addition, many offices synchronize the clocks in a building to a central time server, but this is a luxury most homes do not have. But wouldn't it be nice if every clock in the house could find a correct, central clock and set itself? In this section, we'll walk through the steps of setting up a Jini system that will do this for some "software" clocks. No real clocks currently support Jini, but it would be nice if they did!
The first step is to get the Jini classes, which you can download from http://www.jini.org by following the "Getting Started" link to the Jini Downloads page. This page has several options; you only need the Jini Technology Starter Kit for now, but you may like to download other projects as well.
The Starter Kit installation process for platforms such as Windows and Linux will check your network settings and Java installation, and start up a key component of Jini called a registrar. Once you see a window called Service Browser with the message "1 registrar, not selected," you'll know this key component is running and you can start up some services and clients. You should see something similar to Figure 1-1.
At later times, you can get to this page by just running the command LaunchAll from the installverify directory.
At this stage, you will use three files in the Jini directories:
jsk-lib.jar, in the lib directory, contains many of the Jini classes.
jsk-platform.jar, in the lib directory, contains more Jini classes.
jsk-all.policy, in the installverify/support directory, controls Jini security, and here just turns it off. (This is OK for the purposes of this demonstration, but not for real systems!)
As you already know, this book is all about how programmers can build Jini services and clients. The flashing clocks problem has all the source code explained in Chapter 18. For now, you can download .jar files containing all the compiled classes from http://jan.newmarch.name/java/jini/tutorial/programs.zip. Unzip the files into any directory you want. Three .jar files are of interest, under the dist directory:
clock.clock.ticker.jar: This file contains the class files for a standard "dumb" clock that starts off with a random time and just ticks away. However, it is smart enough to look around the network to see if there are any other clocks it can synchronize with.
clock.clock.computer.jar: This file is a "smarter" clock that gets its time from the built-in computer clock, which we assume has the correct time. This clock also looks around the network to see of there are clocks that should synchronize with it.
clock.clock-dl.jar: This file contains special classes that can be downloaded across the network. Systems like CORBA and web services rely on getting references to remote services and making calls using specific protocols by these references. Jini, on the other hand, relies on downloading Java classes representing a service: once a client has these classes, then it just makes local calls and doesn't care how the downloaded classes talk to the service.
When clients find services, they download a proxy for the service. Support code for this proxy is usually in a .jar file on an HTTP server. So the file clock.clock-dl.jar has to be on an HTTP server somewhere. You can copy this file to an HTTP server you have access to, or you can just use the file on the HTTP server that I run at jan.newmarch.name. (If you have a firewall between my server and your computers, then it may be easier to put the file on a local server than to get Java to talk through the firewall. You can get away with not using these classes in this example; the clocks will work fine, but the service browser won't see the services properly.)
That's all you need to get this demonstration working. You can start up a flashing clock by running Java from, say, a command box under Windows or a terminal window under Unix. You will need to set your classpath so that it contains the Jini files jsk-platform.jar and jsk-lib.jar, and also the clock file clock.clock.ticker.jar. For example, under Unix you could run
JINI_HOME=... CLOCK_DIR=... CLASSPATH=$JINI_HOME/lib/jsk-lib.jar:$JINI_HOME/lib/jsk-platform.jar:$CLOCK_DIR/clock.clock.ticker.jar export CLASSPATH
and under Windows, you could run
set JINI_HOME = ... set CLASSPATH = %JINI_HOME%/lib/jsk-lib.jar;%JINI_HOME%/lib/jsk-platform.jar;%CLOCK_DIR%/clock.clock.ticker.jar
After setting the classpath, run a dumb ticking clock:
java \ -Djava.rmi.server.codebase=http://jan.newmarch.name/classes/clock.clock-dl.jar \ -Djava.security.policy=JINI_HOME/installverify/support/jsk-all.policy \ clock.clock.TickerClock \ "Ticking Clock"
where JINI_HOME is replaced by the directory name where you installed Jini. The first parameter (codebase) lets the service tell clients where the downloadable files are; the second parameter (security) sets the policy for what remote code is allowed to do to this service. The third parameter is the main class file, and the last parameter is just a string to be displayed as window title.
You should see a clock like the one shown in Figure 1-2, flashing every second.
You can run this command as often as you want, on the same or different machines. Each one should start up a new flashing clock. These clocks will all discover one another, but since none of them shows a valid time, there is nothing they can do to each other.
Now start up a "smart" clock that is showing the right time. The classpath needs to be set to the Jini files jsk-platform.jar and jsk-lib.jar again, but this time it should include clock.clock.computer.jar instead of clock.clock.ticker.jar. The you run the good clock as follows:
java \ -Djava.rmi.server.codebase=http://jan.newmarch.name/classes/clock.clock-dl.jar \ -Djava.security.policy=JINI_HOME/installverify/support/jsk-all.policy \ clock.clock.ComputerClock \ "Computer Clock"
As this one starts up, it will discover the other clocks and they will discover it. The wrong clocks will ask the right clocks for the correct time; the right clocks will tell the wrong clocks to reset their time. This is a peer-to-peer system, and I don't know whether right tells wrong the correct time or wrong gets the correct time from right - it doesn't matter. All that matters is that the correct time will soon show on all clocks. Later, the clocks will "drift," but after reading Chapter 18 you will easily be able to add code to resynchronize on a regular basis.
If you now start up another possible flashing clock, it will quickly discover the other correct clocks and may not even flash at all.
So, what is going on with these clocks that is valuable to a distributed application's programmer?
The clocks demonstrate discovery . New clocks start and both discover and are discovered by existing clocks. This is a general property of Jini: clients discover services they are interested in.
A clock can make a call on another clock to get or set the time. The clocks are making remote method calls, but as you will discover later, the protocol isn't specified by Jini: all each clock knows is that it has a local proxy representing the remote service and is making local calls on that proxy. How the proxy talks to its service is of no interest to the client. Of course, it is of interest to the service programmer, and Jini allows the service programmer full control of how this is done, while giving default mechanisms good enough for many cases.
Some clocks can crash and the others will carry on. Well, OK, there isn't much interaction going on. But a clock can crash after but before being called. Jini will throw exceptions to signal failed calls so that the client programmer can handle failure.
While method calls are synchronous, Jini also allows events to be generated and delivered asynchronously to listeners. When a clock changes state, it can inform any interested listener. So Jini can handle both synchronous and asynchronous method calls.
Finally in this section, let's look at pseudocode for the clocks:
main: allow remote code to be downloaded and run within this VM start a thread to asynchronously discover proxies for clock services, calling us as listener service discovered: if we are invalid and the remote clock is valid set our time from the remote clock set state to valid else if we are valid and the remote clock is invalid set the time on the remote clock
That's it! The rest of the clocks' code (less than 700 lines total) is the service specification, user interface classes, and code to keeping the clocks ticking.