ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

First Contact: Is There Life in JavaSpace?
Pages: 1, 2, 3

There are three basic steps to "first contact" in the Jini network.



  • Discovery
  • Join
  • Lookup

There are many options and alternative techniques available to implement these three processes. We will focus on the LookupDiscovery and the JoinManager classes.

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. In our example Ian and Elliot were using the JOS service for their collaboration. Ian would have registered the service with his local LUS in London.

The basic operations of discovering the lookup service are implemented by a Jini technology infrastructure software class. 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. In our example the JOS service registers itself with a local instance of this class. You 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.

Join.

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.

  • java.lang.Object -- The object or service to be registered
  • net.jini.core.entry.Entry[] -- An array of attributes associated with the object
  • 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.
  • 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.
  • 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.

This code fragment demonstrates use of JoinManager. This is our DiscoveryListener implementation. It receives notification of LUSes discovered and discarded. Our implementation creates a new thread to handle the event.

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 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 < registrars.length; 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(); } 
 
  } 
}

This is our ServiceIDListener implementation. This method receives notification of a new ServiceID assignment. Our implementation uses an instance of ReliableLog to capture and restore the unique service id.

net.jini.lookup.ServiceIDListener

public void serviceIDNotify(ServiceID serviceID) {  
 System.out.println("Notification of service id: " + serviceID);     
 this.id = serviceID;  
 try {       
     // capture the id to persistent storage
     log.snapshot();  
	  } catch (Exception e) { e.printStackTrace(); }         
 System.out.println("updated log file with: "+serviceID);        
}

At this point we have discovered the lookup services and registered an object with each service. It is now possible for a client to find the service through the lookup process.

Lookup "first contact"

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. When Elliot requested the JOS he qualified the service match with an Address and Location attribute.

Elliot used his visual transporter to find the service by invoking another Jini infrastructure class, net.jini.core.discovery.LookupLocator. 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.

This chart defines the steps after the service provider has discovered the local LUS.

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

There are two more services that must be configured and started to enable our JavaOffice Space. The transaction service (mahalo) and the JavaSpaces service (outrigger).

Pages: 1, 2, 3

Next Pagearrow