Chapter 1: Overview of Jini

Jini grew from early work in Java to make distributed computing easier. It intends to make "network devices" and "network services" into standard components of everyone's computing environment. The computing world is currently abuzz with "service oriented systems", and Jini has been a major platform for service oriented computing since its inception, long before the term became popular.

Jini supports both software and hardware services. When you buy a new piece of office computing equipment such as a desk lamp, or a new home computer appliance such as an alarm clock, it will not only carry out its ``traditional'' functions but will also join into a network of other computer devices and services. The desk lamp will turn itself off when you leave your desk, informed by sensors in your chair; the alarm clock will tell your coffee maker to switch on a few minutes before it wakes you up. These hardware services will interact with software services such as calendar and diary services and possibly with external services such as weather and stock exchange services (to wake you up early if the weather is cold, or there is sudden movement on the market). Jini doesn't care what is behind services, but just makes them available to applications.

Homes, offices and factories are becoming increasingly networked. Current twisted pair wiring will remain, but will be augmented by wireless networks and networks built on your phone lines and power cables. On top of this will be an infrastructure to allow services to communicate. TCP/IP will be a part of this, but will not be enough. There will need to be mechanisms for service discovery, for negotiation of properties, and for event signalling (``my alarm has gone off - does anyone want to know?'').

Jini supplies this higher level of interaction. This chapter gives a brief overview of the components of a Jini system and the relationships between them.

The licensing model for Jini has now changed to an open source Apache license from a proprietary license. This change, plus the continued quality of the middleware has sparked renewed interest in Jini.

1.1. Jini

Jini is the name for a distributed computing environment, that can offer ``network plug and play''. A device or a software service can be connected to a network and announce its presence, and clients that wish to use such a service can then locate it and call it to perform tasks. Jini can be used for mobile computing tasks where a service may only be connected to a network for a short time, but it can more generally be used in any network where there is some degree of change. There are a large number of scenarios where this would be useful:

  1. A new printer can be connected to the network and announce its presence and capabilities. A client can then use this printer without having to be specially configured to do so.

  2. A digital camera can be connected to the network and present a user interface that will not only allow pictures to be taken, but it can also be aware of any printers so that the pictures can be printed.

  3. A configuration file that is copied and modified on individual machines can be made into a network service from a single machine, reducing maintenance costs.

  4. New capabilities extending existing ones can be added to a running system without disrupting existing services, or without any need to reconfigure clients.

  5. Services can announce changes of state, such as when a printer runs out of paper. Listeners, typically of an administrative nature, can watch for these changes and flag them for attention.

Jini is not an acronym for anything, and does not have a particular meaning. (though it gained a post hoc it gained an interpretation of ``Jini is not initials''.) A Jini system or federation is a collection of clients and services all communicating by the Jini protocols. Often this will consist of applications written in Java, communicating using the Java Remote Method Invocation mechanism. Although Jini is written in pure Java, neither clients nor services are constrained to be in pure Java. They may include native code methods, act as wrappers around non-Java objects, or even be written in some other language altogether. Jini supplies a ``middleware'' layer to link services and clients from a variety of sources.

When you download a copy of ``Jini'', you get a mixture of things. Firstly, Jini is a specification of a set of middleware components. This includes an API (Application Programmer's Interface) so that you as a programmer can write services and components that make use of this middleware. Secondly, it includes an implementation (in pure Java) of the middleware, as a set of Java packages. By including these in the classpath of your client or service you can invoke the Jini middleware protocols to join in a Jini djinn. You also get source code to these packages as a bonus! Finally, Jini requires a number of ``standard'' services, and Sun gives basic implementations of each of these. These implementations are not an official part of ``Jini'', but are included to get you going. In practice, most users are finding these sufficient to do substantial work with Jini.

1.2. Eight Fallacies of Distributed Computing

Since early days, computers have been linked in networks. The mantra from Sun Microsystems has been "the network is the computer" and this has been a cornerstone of much work in distributed computing. Based on this experience, Peter Deutsch took a critical look at the state of distributed computing in 1999 and concluded that early optimism was in many ways misplaced. Networks and applications that run on them are prone to all sorts of problems that do not occur with standalone applications, and attempts to ignore these problems just lead to unreliable and unstable applications. He identified the following fallacies of networking (extended by XXX):

  1. The network is reliable
  2. Bandwidth is infinite
  3. The network is secure
  4. Topology doesn't change
  5. There is one administrator
  6. Transport cost is zero
  7. The network is homogeneous
  8. Latency is zero

1.3. Success Stories

The reader should be aware that Jini is only one competitor in a non-empty market. What conditions the success or failure of Jini is partly the politics of the market, but also (hopefully!) the technical capabilities of Jini, and this book will deal with some of the technical issues involved in using Jini. Jini has been around since 1999, and while it has achieved some notable successes, it does not have the visibility of many other middleware systems. In part, this is because Jini simply works, and has been a stable but evolving platform over these years.

The Sun page http://www.sun.com/software/jini/news/success.xml lists many successful projects using Jini. This section covers a couple of them plus some other systems. For more stories, visit the web page.

Frank Sommers reports on a banking system developed by Rubean, A. G. in an article at http://www.artima.com/lejava/articles/banking_on_jiniP.html . A group of German and Swiss banks with 35,000 customers run a centralised J2EE system. However, this system needs to interact with ATM machines, cash dispensing machines and other devices linked to PCs typically through an RS232 cable. These devices have differing capabilities, their PCs are not always on and have IP addresses assigned by DHCP so that they are continually changing. This dynamic environment could be a maintenance nightmare to a centralised system. The solution by Rubean uses Jini services running on each PC, talking to the devices using the Comms API. Each service advertises itself to Jini lookup services which can handle the dynamic nature of the services without needing configuration. The J2EE system just sees collections of services and is unaware of configuration details.

Magneti Marelli Motorsport builds monitoring equipment for Formula One racing cars, and its hardware and software is used by most racing teaams. However, their software ran on proprietary platforms and lacked the flexibility and robustness they required. In the cars, sensors collect much information that is relayed by radio links to teams in the pits. The environment there is often hot and noisy, and real-time responses are needed to deal both with the data itself and with a changing environment (computers die, network cables are tripped over, etc). New software was develpoed using not only the discovery mechanisms of Jini but also its ability to self-heal the service environment. Being able to run in multiple operating system environments was also a help. The project is described at http://wiki.javapolis.com/confluence/display/JP05/Formula+One+Telemetry+with+Java

Nedap is a security management company used by over 6 million people every day. Some years ago they saw the need for a next generation of security systems and began to design one from the ground up. The heart of their system is a 64M controller with ethernet connection to the network and CAN connection to devices. Each controller exposes itself to the network as a Jini service. Examples of use include the security system controlling elevators within the Eiffel Tower in Paris. Everytime a lift comes within wireless range of a Jini lookup service, it is discovered. This allows security access of a lift to any floor to be controlled, with Jini dynamic service management handling access to services. This system is described at http://www.jini.org/meetings/eighth/J8abstracts.html#Wegman

The previous examples seem to suggest that Jini is just for linking hardware systems into software systems. Jini is certainly good at doing this, since it makes the devices appear as services, making them first class citizens in a service-oriented system. But that is not all that Jini is good for: it is a framework for service-oriented middleware, and excels in purely software-based systems too. An example is Orbitz, a multi-billion dollar online travel company, based in the US. Orbitz uses over a thousand Linux servers, and has both a changing set of machines and evolving applications running on them. For example, if a supplier is having a sale, Orbitz will allocate more services to that company. Obviously, this could be an ongoing horrific task reconfiguring applications to use new services, but Jini dynamic discovery allows this to be done transparently. In addition, services can be upgraded in place and the new versions become automatically available. Their system is described at http://www.sun.com/software/jini/news/Jini_Orbitz_Profile_Final.pdf

Orange is a major mobile communications company, with over 44 million customers worldwide. It offers a range of services, many of them supplied by external organisations. Again, this is a dynamic service environment, with new services begin deployed and existing services being revised, all in a high-volume environment. Again Jini, manages many aspects of this dynamism automatically. See http://www.sun.com/products-n-solutions/telecom/docs/orangesp_1.pdf

These systems often have to deal directly with the issues raised by the Eight Fallacies. For example, they need to work in changing topologies, unreliable networks and limited bandwidth. Jini is middleware designed to manage such issues. It is not perfect. For example, Magneti Marelli needed to tweak parts of Jini to give near real-time responses to failure instead of a default 5 minute failure time. Nevertheless, it recognises the Fallacies and gives mechanisms adequate for many systems with the possibility of sophisticated configuration for more demanding situations.

1.4. Jini in One Hour

Our homes are becoming full of more and more complex pieces of electronic equipment: TVs, microwaves, hifi systems, etc, and many of these have clocks. It is almost as common to find one or more of these clocks "flashing" - particularly on the VCR. Whenever there is a power failure all the clocks start up with an incorrect time and signal this by flashing until they are manually corrected.

Many offices synchronise the clocks in a building to a central time server, but this is a luxury not allowed to most homes. But wouldn't it be nice if every clock in the house could find a correct clock and set itself? In this section we go 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. These are downloadable from the home page of http://www.jini.org by following the link to Jini Technology Starter Kit Downloads. This leads you to a page with several optins. You only need the Technology Starter Kit but you may like to download the examples as well.

The installation process for platforms such as Windows and Linux will check your network settings and Java installation and will start up a key component of Jini called a "registrar". Once you see a window headed "Service Browser" with a message "1 registrar, not selected" then this key component is running and you can start running some services and clients. You should see something like this:.

At later times, you can get to this by just running the command LaunchAll from the installverify directory.

At this stage there are three files in the Jini directories that you will use. They are

  1. jsk-lib.jar in the lib directory contains many of the Jini classes

  2. jsk-platform.jar in the lib directory contains more of the Jini classes

  3. jsk-all.policy in the installverify/support directory. This file controls Jini security, and here just turns it off - okay for this demonstration, not for real systems!

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. But for now, you can download jar files containing all the compiled classes from http://jan.newmarch.name/java/jini/tutorial/programs.zip . Unzip these into any directory you want. There are three jar files of interest, under the dist directory:

  1. clock.clock.ticker.jar

  2. clock.clock.computer.jar

  3. clock.clock-dl.jar

These files are as follows:

  1. clock.clock.ticker.jar contains the class files for a standard "dumb" clock thst 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 that it can synchronise with.

  2. clock.clock.computer.jar is a "smarter" clock that gets its time from the inbuilt computer clock which we assume has the correct time. This clock also looks around the network to see of there are clocks which should synchronise with it.

  3. 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 without using these classes in this example - the clocks will work okay, but the service browser won't see the services properly.)

That's all you need to get a 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

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 under Linux by

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"
and under Windows by

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"
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; the last parameter is just a string to be displayed as window title.

You should see a clock such as this, 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 that 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 should include clock.clock.computer.jar instead of clock.clock.ticker.jar. The you run the good clock by


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 or wrong get 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 re-synchronise 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.

What is going on with these clocks that is valuable to a distributed application's programmer?

  1. 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.
  2. 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.
  3. Clocks can crash and the others will carry on. Well, okay, 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.
  4. 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, we 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 keeping the clocks ticking.

1.5. Components

Jini is just one of a large number of distributed systems architectures, including industry-pervasive systems such as CORBA, DCOM and more recently Web Services. It is distinguished by paying particular attention to the Eight Fallacies and dealing with these issues rather than ignoring them. In addition, it is based on Java, and deriving many features purely from this Java basis. One of the later chapters discusses bridging between Jini and CORBA, as an example of linking these different distributed architectures.

There are many other middleware systems. Each of them is designed for a particular domain of application. Universal Plug 'n Play (UPnP) is designed for a world of devices such as light switches and alarm systems. It does not deal with services in general, such as software services. Web Services are intended to cover the space of long-lived stable services with fixed addresses and do not handle transient services well. Jini is designed for networks in which failure may occur, or where services and clients have a more volatile nature.

In a running Jini system, there are three main players. There is a service, such as a printer, a toaster, a marriage agency, etc. There is a client which would like to make use of this service. Thirdly, there is a lookup service which acts as a broker/trader/locator between services and clients (The generic term for this seems to be settling on service cache manager). There is an additional component, and that is a network connecting all three of these, and this network will generally be running TCP/IP. (The Jini specification is fairly independent of network protocol, but the only current implementation is on TCP/IP.) See figure 1.1.

Code will be moved around between these three pieces, and this is done by marshalling the objects. This involves serializing the objects in such a way that they can be moved around the network, stored in this "freeze-dried" form, and later reconstituted by using included information about the class files as well as instance data. This is done using Java's socket support to send and receive objects.

In addition, objects in one JVM (Java Virtual Machine) may need to invoke methods on an object in another JVM. Often this will be done using RMI (Remote Method Invocation), although the Jini specification does not require this and there are many other possibilities.

Figure 1.1: Components of a Jini system

1.6. Service Registration

A service is a logical concept such as a blender, a chat service, a disk. It will turn out to be usually defined by a Java interface, and commonly the service itself will be identified by this interface. Each service can be implemented in many ways, by many different vendors. For example, there may be Joe's dating service, Mary's dating service or many others. What makes them the "same" service is that they implement the same interface; what distinguishes one from another is that each different implementation uses a different set of objects (or maybe just one object) belonging to different classes.

A service is created by a service provider. A service provider plays a number of roles:

  1. It creates the objects that implement the service

  2. It registers one of these - the service object with lookup services. The service object is the "publically visible" part of the service, and will be downloaded to clients

  3. It stays alive in a server role, performing various tasks such as keeping the service "alive".

In order for the service provider to register the service object with a lookup service, the server must first find the lookup service. This can be done in two ways: if the location of the lookup service is known, then the service provider can use unicast TCP to connect directly to it. If the location is not known, the service provider will make UDP multicast requests, and lookup services may respond to these requests. Lookup services will be listening on port 4160 for both the unicast and multicast requests. (4160 is the decimal representation of hexadecimal (CAFE - BABE). Oh well, these numbers have to come from somewhere.) When the lookup service gets a request on this port, it sends an object back to the server. This object, known as a registrar, acts as a proxy to the lookup service, and runs in the service's JVM (Java Virtual Machine). Any requests that the service provider needs to make of the lookup service are made through this proxy registrar. Any suitable protocol may be used to do this, but in practice the implementations that you get of the lookup service (e.g from Sun) will probably use RMI.

What the service provider does with the registrar is to register the service with the lookup service. This involves taking a copy of the service object, and storing it on the lookup service as in figures 1.2, 1.3 and 1.4.

Figure 1.2: Querying for a service locator
Figure 1.3: Registrar returned
Figure 1.4: Service uploaded

1.7. Client Lookup

The client on the other hand, is trying to get a copy of the service into its own JVM. It goes through the same mechanism to get a registrar from the lookup service. But this time it does something different with this, which is to request the service object to be copied across to it. See figures 1.5, 1.6, 1.7, and 1.8.

Figure 1.5: Querying for a service locator
Figure 1.6: Registrar returned
Figure 1.7: Asking for a service
Figure 1.8: Service returned

At this stage there is the original service object running back on its host. There is a copy of the service object stored in the lookup service, and there is a copy of the service object running in the client's JVM. The client can make requests of the service object running in its own JVM.

1.8. Proxies

Some services can be implemented by a single object, the service object. How does this work if the service is actually a toaster, a printer, or controlling some piece of hardware? By the time the service object runs in the client's JVM, it may be a long way away from its hardware. It cannot control this remote piece of hardware all by itself. In this case, the implementation of the service must be made up of at least two objects, one running in the client and another distinct one running in the service provider.

The service object is really a proxy, which will communicate back to other objects in the service provider, probably using RMI. The proxy is the part of the service that is visible to clients, but its function will be to pass method calls back to the rest of the objects that form the total implementation of the service. There isn't a standard nomenclature for these server-side implementation objects. I shall refer to them in this book as the "service backend" objects.

The motivation for discussing proxies is when a service object needs to control a remote piece of hardware that is not directly accessible to the service object. However, it need not be hardware: there could be files accessible to the service provider that are not available to objects running in clients. There could be applications local to the service provider that are useful in implementing the service. Or it could simply be easier to program the service in ways that involve objects on the service provider, with the service object being just a proxy. The majority of service implementations end up with the service object being just a proxy to service backend objects, and it is quite common to see the service object being referred to as a service proxy. It is sometimes referred to a the service proxy even if the implementation doesn't use a proxy at all!

The proxy needs to communicate with other objects in the service provider. It appears we have a chicken-and-egg situation: how does the proxy find the service backend objects in its service provider? Use a Jini lookup? No, when the proxy is created it is "primed" with its own service provider's location so that when run it can find its own "home". This will appear as in figure 1.9

Figure 1.9: A proxy service

How is the proxy primed? This isn't specified by Jini, and can be done in a large number of ways. For example, an RMI naming service can be used such as rmiregistry, where the proxy is given the name of the service. This isn't very common, as RMI proxies can be passed more directly as returned objects from method calls, and these can refer to ordinary RMI server objects or to RMI activatable objects. Or the proxy can be implemented without any direct use of RMI, and can then use an RMI exported service or some other protocol altogether such as ftp, http or a home-grown protocol. These various possibilities are all illustrated in later chapters.

1.9. Client Structure

Internally a client will look like

Pseudocode Where discussed
prepare for discovery Discovering a lookup service
discover a lookup service Discovering a lookup service
prepare a template for lookup search Entry objects and Client search
lookup a service Client search
call the service

The following code is simplified from the real case, by omitting various checks on exceptions and other conditions. It attempts to find a FileClassifier service, and then calls the method getMIMEType() on this service. The full version is given in a later chapter. We don't give detailed explanations right now, this is just to show how the above schema translates into actual code.

 package nonworking;

public class TestUnicastFileClassifier {

    public static void main(String argv[]) {
	new TestUnicastFileClassifier();
    }

    public TestUnicastFileClassifier() {
	LookupLocator lookup = null;
	ServiceRegistrar registrar = null;
	FileClassifier classifier = null;

        // Prepare for discovery	
        lookup = new LookupLocator("jini://www.all_about_files.com");

        // Discover a lookup service
        // This uses the synchronous unicast protocol
	registrar = lookup.getRegistrar();

        // Prepare a template for lookup search
	Class[] classes = new Class[] {FileClassifier.class};
	ServiceTemplate template = new ServiceTemplate(null, classes, null);

        // Lookup a service
	classifier = (FileClassifier) registrar.lookup(template);

        // Call the service
	MIMEType type;
	type = classifier.getMIMEType("file1.txt");
        System.out.println("Type is " + type.toString());
    }
} // TestUnicastFileClassifier

 

1.10. Server Structure

A server application will internally look like
Pseudocode Where discussed
prepare for discovery Discovering a lookup service
discover a lookup service Discovering a lookup service
create information about a service Entry objects
export a service Service registration
renew leasing periodically Leasing

The following code is simplified from the real case, by omitting various checks on exceptions and other conditions. It exports an implementation of a file classifier service, as a FileClassifierImpl object. The full version is given in a later chapter. We don't give detailed explanations right now, this is just to show how the above schema translates into actual code.

 package nonworking;


public class FileClassifierServer implements DiscoveryListener {
    
    protected LeaseRenewalManager leaseManager = new LeaseRenewalManager();

    public static void main(String argv[]) {
	new FileClassifierServer();

        // keep server running (almost) forever to 
	// - allow time for locator discovery and
	// - keep re-registering the lease
        Thread.currentThread().sleep(Lease.FOREVER);

    }

    public FileClassifierServer() {
	LookupDiscovery discover = null;

        // Prepare for discovery - empty here

        // Discover a lookup service
        // This uses the asynchronous multicast protocol,
        // which calls back into the discovered() method
        discover = new LookupDiscovery(LookupDiscovery.ALL_GROUPS);

        discover.addDiscoveryListener(this);
    }
    
    public void discovered(DiscoveryEvent evt) {
        ServiceRegistrar registrar = evt.getRegistrars()[0];
        // At this point we have discovered a lookup service

        // Create information about a service
	ServiceItem item = new ServiceItem(null,
         				   new FileClassifierImpl(), 
					   null);

        // Export a service
	ServiceRegistration reg = registrar.register(item, Lease.FOREVER);

	// Renew leasing
	leaseManager.renewUntil(reg.getLease(), Lease.FOREVER, this);
    }
} // FileClassifierServer
 

1.11. Partitioning an Application

Jini uses a "service" view of applications. This is in contrast to the simple object-oriented view of an application. Of course, a Jini ``application'' will be made up of objects, but these will be distributed out into individual services, which will communicate via their proxy objects. The Jini specification claims that in many monolithic applications there are one or more services waiting to be released, and making them into services increases their possible uses.

To see this, we can look at a "smart file viewer". This is an application that will be given a filename, and based on the structure of the name will decide what type of file it is (.rtf is Rich Text Format, .gif is a GIF file, and so on). Using this classification it will then call up an appropriate viewer for that type of file, such as an image viewer or document viewer. A UML class diagram for this might look like figure 1.10

Figure 1.10: UML diagram for an application

There are a number of services in this. Classifying a file into types is one (which will be used heavily in the sequel - because it is simple). This service can be used in lots of different situations, not just viewing contents. Each of the different viewer classes is another. This is not to say that every class should become a service! That would be overkill. What makes these qualify as services is that they

  1. have a simple interface

  2. are useful in more than one situation

  3. can be replaced or varied

They are reusable, and this is makes them good candidates for services. They do not require high-bandwidth communication, and are not completely trivial.

If the application is re-organised as a collection of services, then it could look like figure 1.11

Figure 1.11: Application as a collection of services
Each service may be running on a different machine on the network (or on the same machine - it doesn't matter). Each exports a proxy to whatever service locators are running. The SmartViewer application finds and downloads whatever services it needs, as it needs them.

1.12. Support Services

The three components of a Jini system are clients, services and service locators, which may run anywhere on the network. These will be implemented using Java code running in Java Virtual Machines (JVM). The implementation may be in pure Java but it could make use of native code by 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 to 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.

1.12.1 HTTP server

A Java object running as a service has a proxy component exported to the service locators and then onto a client. It passes through one 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 snaphot 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. Where is the code? This is one of the places where a distributed Jini application differs from many other distributed systems: 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.

So 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 provider specifies the protocol used 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 there also. This often means 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 to 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.

1.13. The End of Protocols

Client-server systems built from scratch typically require the design of a communications protocol. For example, before the web could became as important as it is today, the "hyper-text transport protocol" HTTP had to be designed so that clients and servers could communicate. This protocol has been through several public versions: 0.9, 1.0 and 1.1. Clients and servers have had to be rebuilt on each version change of even this simple procotol

RPC systems such as Sun's ONC, CORBA, COM+ and more recently SOAP also rely on a fixed protocol. In these cases though, there are usually tools which will generate code to manage the protocol messaging. However, these tools need to generate two sets of code: one for the client-side and one for the server-side. Any change to the protocol means that both client and server have to have this code regenerated.

This dependence on protocol is tightly bound to how clients address services, which depends on how they find these services. For example, to address a Web service you often need a WSDL document which contains the URL of the service's server and method names of the service. Coupled with knowledge that the service is addressed using SOAP, a client can then talk to it. With CORBA, in a variety of ways you could obtain an object reference (through a name server, using "stringified" references or through a trader). Given this reference and the knowledge that CORBA uses the IIOP protocol, a client could then talk to a server.

Protocol changes are a nightmare once it has become a popular system. It took years for all clients and servers to upgrade to HTTP 1.1 and similarly for CORBA protocol changes. Some protocols such as that used by sendmail haven't been touched for years because of the chaos to email that would almost certainly result in any changes, even though many people think it is well past its use-by date.

When you discover a Jini service, you don't get an address to be dealt with by a particular protocol. Instead you get a Java proxy object with known methods. This alters the playing field in a significant way: the client doesn't need to know the communications protocol at all! It just makes local method calls on the proxy.

The proxy comes from the server, and this is key to client ignorance. The client doesn't know the protocol used between proxy and service since it never has to know. The communications protocol is private to the proxy and the service. That means that the proxy and the service can use any protocol they wish, and it has no effect on the client at all. The proxy and service can change the protocol, and the client never knows.

There is often an assumption that Jini systems must be "all Java". This isn't quite true. Certainly the client has to be a Java client, although even here there are caveats: strictly, the client must be able to invoke a Java object through a Java Virtual Machine and there are many languages that can now do this. The proxy needs to be JVM bytecodes. Most likely this will be generated from Java source code, but not necessarily. But on the service side, who knows? The proxy can talk to any service it wants to, using any protocol it has chosen. For example, many people (including the author) have built proxies that will talk SOAP to UPnP devices or Web Services. The client is ignorant of the service language and has no need to care.

It isn't quite the "end of protocols" unfortunately. Jini leads to the end of client knowledge of invocation protocols, but the client still has to discover the Jini proxy. There is still a discovery protocol involved. However, the Jini discovery protocol is fairly lightweight and is customised to just this task rather than being a general-purpose protocol. Jini discovery involves a simple protocol to discover a lookup service and then a mechanism for downloading bytecodes. In the last section we pointed out the use of an HTTP server to deliver these proxy bytecodes, but this is not a prescribed mechanism for Jini. It would be possible to use other mechanisms such as email or ftp, although I don't think anyone has yet seriously considered doing this since HTTP seems to be good enough so far.

1.14. Summary

A Jini system is made up of three parts

  1. Service

  2. Client

  3. Service locator

Code is moved between these applications. A registrar acts as a proxy to the lookup locator, and runs on both the client and service.

A service and a client both possess a certain structure, which is detailed in the following chapters. Services may require support from other non-Jini servers, such as an HTTp server.

1.15. Copyright

If you found this chapter of value, the full book "Foundations of Jini 2 Programming" is available from APress or Amazon .

This file is Copyright (©) 1999, 2000, 2001, 2003, 2004, 2005 by Jan Newmarch (http://jan.newmarch.name) jan@newmarch.name.

Creative Commons License This work is licensed under a Creative Commons License, the replacement for the earlier Open Content License.