Jini™ technology is a service oriented architecture that defines a programming model which both exploits and extends Java™ technology to enable the construction of secure, distributed systems consisting of federations of well-behaved network services and clients. Jini technology can be used to build adaptive network systems that are scalable, evolvable and flexible as typically required in dynamic computing environments.
Steps to contact the Jini World
There are three basic steps to first contact in the Jini network.
- Discovery
- Join
- Lookup
Discovery
The process of discovery occurs when a service is searching for a registration point in the Jini network. This registration point or service is referred to as the Lookup Service (LUS). The Lookup Service is fundamental to the Jini network. It allows us to manage the life cycle of services. Services must register with a LUS in order for other services and clients to find and use them.The net.jini.discovery.LookupDiscovery class implements the net.jini.discovery.DiscoveryManagement interface. This interface defines operations related to the discovery of a lookup service. An instance of the LookupDiscovery class acts as a mediator between devices and services and the LUS supporting the network.
You can construct an instance of this class by passing an array of groups that you want the discovered lookup service to support. For instance public groups or groups identified by specific department or geographic region could be used to construct the LookupDiscovery class.
String[] groups = new String[] { "" };
try {
LookupDiscovery lookup = new LookupDiscovery(groups);
} catch (IOException ioe) {}
In the previous code fragment the empty string value is used to indicate all public groups.
This instance then multicasts a request on the local network for any lookup services that support the groups requested to identify themselves. The LookupDiscovery instance listens for replies and, if there are any, passes to the service (JOS) an array of objects that are proxies for the discovered lookup services. These proxies are what the service will use to register with the LUSes discovered.
Reggie, the Jini supplied LUS, is one of the services that you start when you establish your Jini network. You may start one or more lookup services on your network. The following batch file provides an example start-up script. The environment variable JINI_HOME points to your installation of Jini.
java -jar -Djava.security.policy=%JINI_HOME%\policy.file %JINI_HOME%\lib\reggie.jar
http://%IP_ADDRESS%:8080/reggie-dl.jar %JINI_HOME%\example\lookup\policy.all %JINI_HOME%\tmp\reggie_log public
Join
The process of Join occurs when a service has located a lookup service through discovery and now wishes to register a service with it. The Join protocol is implemented by another Jini technology infrastructure software class, net.jini.lookup.JoinManager. This class actually combines discovery, the first step, with LUS registration. There are five parameters required to construct a JoinManager.
1)java.lang.Object -- The object or service to be registered
2)net.jini.core.entry.Entry[] -- An array of attributes associated with the object
3)net.jini.lookup.ServiceIDListener or net.jini.core.lookup.ServiceID -- Every service receives a unique service identifier. If the service has already received the identifier from the LUS, then it uses the id as a parameter; otherwise it supplies an id listener to receive the id. The id listener would store the id for subsequent registration.
4)net.jini.discovery.DiscoveryManagement -- This is an interface that defines the discovery operations as outlined in the previous section. The LookupDiscovery class implements this interface. In addition the LookupLocatorDiscovery class implements this interface using unicast instead of the multicast protocol.
5)net.jini.lease.LeaseRenewalManager -- The lease renewal manager is responsible for renewing your lease with the LUS. This is how resources are managed across the Jini network, e.g. time allocation management.
public class MyServer implements ServiceIDListener, DiscoveryListener
{// register with any LUS supporting
public groupsString[] groups = new String[] { "" };// define specific LUS locations for unicast discovery
LookupLocators[] locs = { "jini://%HOST_NAME%:4159" };// define specific service attributes e.g. Name and ServiceInfoprivate
Entry[] entries = { new Name("MyInterface"),new ServiceInfo("My Service Description","","","1.0","", "") };
// supply a lease manager for our serviceLeaseRenewalManager
lrm = new LeaseRenewalManager();// we don't have a service id yet
ServiceID id = null;// table to save service items
private Hashtable lookups = new Hashtable();// the service to register
MyServiceObject obj;
public MyServer() {
try {
if (System.getSecurityManager() == null) {System.setSecurityManager(new RMISecurityManager());}
// the service that you are registering
obj = new MyServiceObject ();
// we will use a unicast and multicast discovery process
LookupDiscoveryManager ldm = new LookupDiscoveryManager(groups, locs, this);
if(id != null)
{// we have a service id
JoinManager jm = new JoinManager(obj, entries, id, ldm, lrm);
} else {
// we will have a service id assigned
JoinManager jm = new JoinManager(obj, entries, this, ldm, lrm);
}
} catch (Exception e) {
e.printStackTrace();
System.out.println("Unable to initialize service...exiting!");
System.exit(1);
}
net.jini.discovery.DiscoveryListener Interface
public void discovered(DiscoveryEvent de) {
new Thread(new DiscoveryNotifier(de)).start();
}
public void discarded(DiscoveryEvent de) {
// removes the LUS from the lookup table
// and may generate additional event notifications
}
Our DiscoveryEvent thread interfaces with the LUS proxy (ServiceRegistrar) to register our service with the LUSes returned.class
class DiscoveryNotifier implements Runnable {
DiscoveryEvent de;
DiscoveryNotifier(DiscoveryEvent de) {
this.de = de;
}
public synchronized void run() {
try {
// get the LUS's returned
ServiceRegistrar registrars[] = de.getRegistrars();
for(int i=0; i <>
if(lookups.containsKey(registrars[i]) == false) {
// create a ServiceItem
ServiceItem si = new ServiceItem(id, obj, entries);
// register the service with the LUS
ServiceRegistration sr = registrars[i].register(si,Long.MAX_VALUE);
System.out.println("registered on " +registrars[i].getLocator() + " as " + sr.getServiceID()); // delegate lease management
lrm.renewUntil(sr.getLease(), Long.MAX_VALUE, null);
// update our LUS table
lookups.put(registrars[i], sr);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
Lookup
The process of Lookup occurs when a client or user needs to locate and invoke a service described by its interface type and option service attributes. A lookup service maps interfaces indicating the functionality provided by a service to sets of objects that implement the service. In addition, descriptive entries associated with a service allow more fine-grained selection of services based on properties. If you look back at the parameters to the JoinManager you will notice an array of attributes as the second parameter. These attributes implement the Entry interface and are used to qualify or augment the object that has been registered. When lookups are performed users can supply attributes to limit the matching services. Entry attributes can be user defined; however, the Jini implementation provides some default attribute classes. The net.jini.lookup.entry package defines the Address, Comment, Location, Name, ServiceInfo, Status, and ServiceType attributes. The LookupLocator class is responsible for performing unicast discovery. A hostname is all that is required to discover the LUS at a specific location. Optionally a port number can be provided to the LookupLocator. Otherwise it will default to port 4160. The LookupLocator constructor takes a URL of the form:
jini://host:port/.
Unicast discovery was used as opposed to multicast because the multicast protocol is restricted by network configurations. The multicast protocol is only used on local network segments. Typically routers block multicast packets across network defined boundaries. This is often a source of confusion with new developers to Jini. The basic pattern of communication involves a combination of multicast and unicast. This enables the best of both worlds: dynamic discovery of local peers and directed or trusted discovery of distant peers.
Objects in a lookup service may include other lookup services; this provides hierarchical lookup. Further, a lookup service may contain objects that encapsulate other naming or directory services, providing a way for bridges to be built between a Jini lookup service and other forms of lookup service.
In step 3 the HTTP server running on the server-side of the Jini network supplies the code to the client requesting the service. This movement of code from machine-to-machine is critical to the differentiation of Jini from other distributed object technologies. The codebase parameter supplied to the HTTP daemon at start-up determines the location of the jar and class files that are available for download distribution.
The following script starts the http server.
java -jar %JINI_HOME%\lib\tools.jar -port 8080 -dir %JINI_HOME%\download\lib -trees -verbose
In step 4 the client invokes methods on the service. Some methods may be invoked locally while others may be invoked remotely. The flexibility provided in the implementation of the service will determine the best invocation approach. Jini uses the Java Remote Method Invocation (RMI) framework to enable communication between services and clients. The infrastructure to support communication between services is not itself a service that is discovered and used but is, rather, a part of the Jini technology infrastructure. RMI provides mechanisms to find, activate, and garbage collect object groups.
RMI allows data and code to be passed from object to object around the network. The simplicity and dynamic capabilities of the Jini system are enabled by this ability to move code around the network in a form that is encapsulated as an object. The RMI daemon is another service that must be started to enable your Jini environment.
The following script starts the RMI
daemon.rmid -J-Djava.security.policy=%JINI_HOME%\policy.file
We now have the basis of a Jini environment in place.
- An HTTP server running with a defined codebase for downloading files.
- An RMI daemon running to activate services
- An LUS (Reggie) running to register and lookup services