Article
monochromata
Issue 5
Jini on the Jnode Java OS
Version 1.2, released June 20, 2005
This article outlines how Jini technology can be used to dynamically and automatically extend the Jnode Java-based OS with components retrieved from the network. After a short outline of the proposed system, the relevant concepts of Jini technology and the Jnode OS are introduced. The article finishes with a practical outlook at the implementation of the proposed extension.
  1. Introduction
  2. Architectural Outline
  3. Jini
    1. Lookup
    2. Discovery
    3. Security
  4. Jnode
    1. Operating System
    2. Plugins
    3. User Interface
  5. Use Cases
    1. Shell Commands
    2. Device Drivers
  6. Desktop Services
  7. Corrections

Introduction

Current operating systems are based on the concept of locally installed applications. Even thought networks are used pervasively, software is run locally and normally needs to be downloaded manually first. Of course there has been great progress in this area. E.g. the Debian Linux distribution provides the apt system that downloads and installs arbitrary applications using only a single command. While this system makes system administration really easy, you still have to interrupt your work when you try to use a shell command that is not installed. Java has a nice system called Java WebStart that allows you to click a link on a website and then automatically downloads and starts the application the link referred to.

What this article is about is to remove the step of explicitly telling the computer to download the missing application, using a mechanism more general than Java WebStart. The mechanism presented here is more general in that it also allows you to use an arbitrary identifier to specify the application you want to download and start. The identifier could be a URL, like in Java WebStart or a name like when you want to execute a shell command.

Depending on how complex the applications are, they can either be cached or be installed locally when they have been downloaded. These are the most common ways to avoid repeated downloading of previously used applications.

Because Jini provides a very powerful service lookup mechanism, it is chosen as the basic services platform. Jini services will be used in this system in the same way normal operating systems use local applications.

Since Jini services are written in Java, those operating systems could benefit most from an integration, that deeply integrate Java. The Jnode project develops a Java-based OS that is itself programmed in Java and is therefore an ideal candidate for running Jini services.

Architectural Outline

Having a look at the proposed system does not only include the computer running the Jnode operating system. Since Jini is used to leverage the applications provided by other computers, these other computers need to be depicted as well.

Image 1: Abstract infrastructure

Having a look at the picture shows three computers. The one running the Jnode OS with its numerous internals and on the right two other hosts, both running a lookup service. (A lookup service is a special-purpose Jini service, similar to a registry, that is used by other services to announce their availability. It is also used by services and clients to find [other] services.) Of course it is possible to use only a single lookup service, but in order to add some redunancy it makes sense to use more. On a large corporate network services may be provided by a set of centrally administered lookup services running on dedicated machines. On a small office, or at home you may share services with your colleagues or friends in a peer-to-peer manner. Hence it is perfectly possible that the two computers running a lookup service also run the Jnode operating system.

Turning to the internals of the machine that runs Jnode, we can see that the lookup services at the remote hosts are not used directly. Instead a LookupCache is used to store previously used services for later reuse. This is a performance optimization to both reduce network traffic as well as perceived latency when looking up services. LookupCaches are commonly used in Jini-based systems. If made persistent, they can have the nice side-effect of providing previously downloaded services when the network is down or the computer is offline for another reason.

The LookupCache itself is used by the Shell and the DeviceManager. Both will serve as use cases later. The shell loads commands using Jini that aren't installed locally. The device manager does so with device drivers. Even thought any command or driver might be available from the network, they may sometimes be needed before network access has been set up. I.e. at least the installer of the OS must contain basic drivers for graphics and network cards etc. - hence the local device drivers and commands.

Jini

Jini was developed and introduced to the market by Sun Microsystems in 1999. Since then a community has been formed that guides the future of the technology. Jini is a service-oriented architecture for network services that addresses some specific problems that are typically experienced in distributed systems.

Contrary to an often cited myth Jini is not specifically for devices. Jini services are simply Java objects that are passed across the network. This allows for a wide variety of service implementations. Services may consist of a single object that performs all work inside the Java Virtual Machine (JVM) that downloaded it. Alternatively a Jini service may consist of a proxy object that is downloaded to the JVM and communicates to a backend server using Java RMI, raw sockets, XML or whatever protocol. Finally there is even the option to have an embedded device, that is not Java enabled, provide a Java object that acts as a proxy to the embedded device.

Together with the members of the Jini community, Sun recently decided to release the upcoming 2.1 version of Jini under the Apache Software License 2.0 and thereby make it open source. While the 2.1beta release is already available and is provided under an ASL 2.0 license, many community projects are still in the process of migrating to the new license.

While Jini also provides concepts like distributed transactions and methods for freeing unused remote resources, the parts used most for integrating Jini into the Jnode operating system are the lookup and discovery specifications which will be introduced in the next two sections.

Lookup

Jini uses lookup services to register and find services. Each Jini service is registered with a lookup service with an accompanying set of attributes. Thereby you can lookup services by specifying a set of Java types the service should implement. Hence you may also find services that implement an interface that is dervied from the interface you are looking for (in opposite to String-based matching used by other systems, that supports only exact match).

Additionally you may look for services that specify a certain set of attributes. These attributes, also called entries, are normal Java objects that are instances of classes that implement the net.jini.core.entry.Entry marker interface. When entries are used to find a matching service, the type implemented by the entries and all their public, non-final, non-static fields are compared. The fields of an entry may not have primitive types (e.g. int or boolean need to be replaced by Integer or Boolean instances).

When querying a lookup service for a particular service, a ServiceTemplate is used that specifies the types matching services need to implement and a set of entries that must have been added to the lookup service together with the service proxy. The entries contained in the ServiceTemplate are used as templates while the lookup query is evaluated to match candidate services. The fields of the template entries may also be set to null, turning them into wildcards (i.e. a value of null in a field in the template entry will match all values of this field in all other entries of the same type).

Image 2: Looking up services

The above image illustrates service lookup. On the left a number of services contained in the lookup service are depicted. The right side shows the template supplied by the client to find one or more matching services. The lookup process starts by examining the Driver service. Since it is not an instance of the Command type required by the template, it doesn't match and will not be part of the set of services returned to the client that issued the lookup query. The second service has the same type as the template and also provides an Alias entry. Nonetheless it doesn't match the template, since the value of the alias field of the entry is "Ping" and not "Date". Fortunately the third service implements the sought type and provides a matching Alias entry. (Note that if the alias field of the template entry would have been null, the second service would also match and be returned to the client.)

The proxies of services registered at a lookup service are stored inside the lookup service in their marshalled (serialized) form. This frees the lookup service from unmarshalling the registered service objects / proxies (they needed to be marshalled to be transported over the network). This is also the reason why proxies and entries are not compared using their equals method, but based on their marshalled representation.

Discovery

Discovery is used by clients and services to find a lookup service. They may search for lookup services on the local network using multicast or may contact a number of lookup services on the internet using unicast. When lookup services have been found using either uni- or multicast, their service proxy (a marshalled Java object) is downloaded and can then be used by the client.

Discovery also supports arbitrarily named groups that can be chosen to partition collections of services into federations.

Security

Since version 2.0, Jini also supports a comprehensive security model. Based on the Java Security Architecture, services may specify which clients may invoke which methods on them and if and how to secure the network connection between proxy and backend. It is also possible that clients dynamically grant permissions to individual services instances (i.e. not to all services of the same type, but to single instances).

Jini also supports a mechanism to gain trust in a proxy from an insecure source. This is neccessary because the proxy may be corrupted on its way through the network. The proxy trust mechanism is described in an interview about Jini security Bill Venners did with Bob Scheifler in 2002.

Jnode

Jnode (the Java New Operating System Design Effort) went public in may 2003. The project is lead by Ewout Prangsma who was working on a number of similar systems before. Jnode is a Java Virtual Machine that does not need another operating system to run inside, but instead runs as OS itself. Development is currently undertaken by a handful of core developers and interested people who commit irregularly. Jnode is released under the LGPL license, so everybody is welcome to contribute.

Most notably is the fact, that besides a small microkernel, everything (even device drivers) is written in Java. This leads to a system that should not suffer from security threads C programs often face (e.g. buffer overflows).

The project recently released the 0.2 release. The project homepage is located at http://www.jnode.org/.

Operating System

Jnode uses the Grub bootloader to load and boot a kernel image. After the bootstrapper code is executed, the JVM is initalized, which is the first time Java code is run. Jnode does not contain any C code. Only the microkernel and small amounts of the VM are written in assembler. The VM supports the standard Java features (GC, multithreading, the Java Security architecture). To implement the Java API, the classpath project is used.

The device drivers in Jnode are also programmed in Java. Right now drivers for graphics- and network cards as well as keyboards, mice, disks and CD-ROM drives are available. Device drivers are currently deployed as plugins (see below).

Jnode is currently a single-user OS. To enhance performance, all Java code executed on Jnode is compiled to native code on-the-fly before it is executed.

Plugins

Jnode uses a custom plugin framework that uses Jar files accompanied by XML descriptors to organize the various parts into a modular system. The jar files contain the classes and resources needed to run the plugin. The descriptor specifies which packages are contained in the plugin and which other plugins are used by it.

The plugin framework also uses the concept of extension points. Plugins can define extension points that other plugins implement. The plugin that provides the extension point can then obtain a list of all plugins that implement the extension point. Among others, the shell currently uses this mechanism to make a list of available commands. Therefore the shell defines an extension point and all commands implement that extension point. When the user enters the name of a command, the shell can then search through the list of available implementations of the command extension point to find a command with the name equal to the one entered by the user.

User Interface

Jnode currently provides a shell that is started when the system has finished the boot process. The shell already allows commands to be run that are implemented as plugins. It is also possible to start Java applications from the shell by entering the name of their main class. To run custom Java applications users may set a custom classpath by using a special shell command.

The graphical user interface is currently in the works. No desktop is available so far.

Use Cases

This section discusses a number of uses cases to show which parts of the Jnode operating system may benefit from using Jini technology. Of course, those parts can benefit most, that are already implemented as kinds of modules or plugins.

Albeit it may be possible to advance the extension points model using Jini, I thought it may be better to stick to less abstract examples (that I understand ;-) ). Therefore I will focus on making shell commmands and device drivers available as Jini services.

Shell Commands

Since there are currently no GUI applications available for Jnode, shell commands are the most application-like entities that can currently be used with Jnode. To make use of all commands that have ever been implemented, without needing to explicitly update the installation when new ones become available, Jini will be used to load commands that aren't available locally.

Jnode commands are Java classes that implement the Command interface. This interface (see below) provides a single method that is used to invoke the command. The arguments entered by the user as well as input-, output- and error streams are provided via the methods parameters.

Code Fragment 1: The Command interface

public interface Command {
    execute(CommandLine commandLine, java.io.InputStream in, java.io.PrintStream out, java.io.PrintStream err) 
}

When Jini services are used as commands, they will also implement the Command interface. This allows the services to be directly used as commands, and enables clients to lookup command services by querying the lookup service for services that implement the command interface.

Image 3: How Jnode commands can be loaded using Jini

Jnode internally uses CommandInvokers to invoke commands. To load Jini services as commands, the DefaultCommandInvoker class is extended to create the JiniCommandInvoker class which uses a LookupCache to lookup services. The invoke method of the CommandInvoker is called when the user entered a command and hit return. When no command with the name given by the user is available locally, the invoke method of the JiniCommandInvoker will use the LookupCache to contact lookup services and query them for a command services with the name entered by the user. Already downloaded command services will be cached locally inside the LookupCache to have them at hand for later invocations and avoid repeated lookups of the same command service.

Of course the JiniCommandInvoker needs to lookup individual commands. Therefore it is not enough to query the lookup services for a list of all services implementing the Command interface. The name (a.k.a. alias) of the command to be found also needs to be added to the lookup query so that only command services with a matching alias are returned.

In order to find a command service for a given alias, the alias entered by the user will be used to create an Alias template entry (according to the right side of the above image) which is in turn added to the template that already specifies that the lookup should return services implementing the Command interface. The first returned command service which is trusted by the user using the proxy trust mechanism will then have its execute method invoked with the provided arguments. If no matching command service was found, an error will be printed to the shell indicating that no command with the given name could be found neither locally, nor on the network.

Device Drivers

Like all other operating systems, Jnode uses device drivers to access all kinds of devices. While Jnode already provides the ability to write platform-independent drivers it would also be nice if the OS would automatically discover drivers for new hardware without requiring a CD to be inserted. Since most computers, once installed, are connected to the internet and broadband connections are speading at a fast pace, it makes perfect sense to load the device drivers from the network. Of course there are exceptions. E.g. no drivers can be loaded from the network during installation when no network card has been installed so far. Hence there will also be a need to have a set of locally installed drivers available.

Similar to the way shell commands are loaded, Jnode already provides a modular device driver architecture that makes it easy to load drivers using Jini if none of the locally available drivers fits for a certain device.

Image 4: How Jnode drivers can be loaded using Jini

Jnode loads drivers using a DeviceManager. This DeviceManager uses a number of DeviceToDriverMappers to load drivers for devices. To load a driver, the DeviceManager successively consults all available DeviceToDriverMappers to find a suitable driver and will use the first driver returned by a DeviceToDriverMapper. To load Jini drivers, a special JiniDeviceToDriverMapper is added to the end of the list of mappers so it is consulted when no driver could be found locally. This special mapper uses a LookupCache to lookup matching driver services from the Jini federation.

Image 5: Classes and entries used to match device drivers

In order to find a driver matching a given device, again Jini entries play a key role. While all driver services will extend the abstract org.jnode.driver.Driver class, it doesn't make much sense to use this class for lookup because it is too broad. To find a specific driver, additional entries will be used, that probably differ depending on the bus (e.g. PCI, PS2, USB) used to connect the device to the host. In the image above the USBInterface entry is shown, that contains diverse identifiers used by USB to identify interfaces implemented by a device. To match a driver to a device, the interfaceClass, interfaceSubClass and interfaceProtocol fields may be used for a lookup query.

Similar to the entries used for matching the shell commands, the entries are derived from classes already used inside Jnode. The existing classes could also be used, but using separate classes is more flexible since both types of classes are made for different purposes. E.g. the USBInterface entry uses Integer instances to represent the various identifiers to comply with the Jini Entry Specification whereas the class it was derived from uses the primitive type int.

Jini also provides a Surrogate Architecture that could potentially be used to load drivers. Unfortunately this architecture needs a custom specification and implementation for every transport (e.g. ethernet or usb). There are already a spec and implementation for a Surrogate Architecture using IP that are used to load Jini services that access embedded devices over the IP protocol. Also efforts to create a USB interconnect specification for using the Surrogate Architecture to load Jini services as kind of drivers for usb devices were restarted recently.

Because device drivers are obviously security sensitive, they provide a good case for the Jini security mechanisms, most notably proxy trust verification, which allows to verify the driver service originates from a trusted provider and hasn't been modified on its way to the client.

Desktop Services

Desktop services are surely another interesting area for connecting Jini and Jnode. Since Jnode doesn't have a desktop so far and Jini is currently also deployed most often for machine-to-machine communication, both technologies are still in their early days with respect to this field. This provides great room for experimentation.

While it may at first sound strange to turn the desktop into a distributed system, this is just an adaption on how desktop computers are used today. Not only is much software downloaded from the internet. Many people also use more than one computer or work in groups that would benefit from being able to easily share Jini services.

This scenario is especially interesting when it come to switching to a new computer. That's a real pain when everything is installed locally. But when you only use services from the network you simply turn off your old machine, turn on the new one and grab the services you were using on the old machine again. There may even be a Jini service that keeps track of your desktop session, and automatically reopens all services you used before.

Corrections

This document is updated from time to time to fix errors and update external links. Below you find a list of these corrections.

Version Date Correction
1.2 06/20/2005 Fixed errors in image 2 (thanks to Andreas Semt)
1.1 06/01/2005 Changed link to the Jnode homepage to http://www.jnode.org
1.0 05/20/2005 Initial publication

Creative Commons License This article is licensed under a Creative Commons License. Jini and Java are trademarks or registered trademarks of Sun Microsystems, Inc. in the U.S. and other countries.
Impressum