previous chapter table of contents next chapter

Building a Cache of Services

A client may wish to make use of a service multiple times. If the client simply found a suitable reference to a service, then before each use it would have to check whether the reference was still valid, and if not, it would need to find another one. The client may also want to use minor variants of a service, such as a fast printer one time and a slow one the next . While this management can be done easily enough in each case, the ServiceDiscoveryManager can supply a cache of services that will do this work for you. This cache will monitor lookup services to keep the cache as up-to-date as possible.

The cache is defined as an interface:

 package net.jini.lookup; public interface LookupCache {     public ServiceItem lookup(ServiceItemFilter filter);     public ServiceItem[] lookup(ServiceItemFilter filter,                                 int maxMatches);     public void addListener(ServiceDiscoveryListener l);     public void removeListener(ServiceDiscoveryListener l);     public void discard(Object serviceReference);     void terminate(); } 

A suitable implementation object can be created by the ServiceDiscoveryManager method:

 LookupCache createLookupCache(ServiceTemplate tmpl,                                   ServiceItemFilter filter,                                   ServiceDiscoveryListener listener); 

We will ignore the ServiceDiscoveryListener until the next section of this chapter. It can be set to null in createLookupCache() .

The LookupCache created by createLookupCache() takes a template for matching against interface and entry attributes. In addition, it also takes a filter to perform additional client-side Boolean filtering of services. The cache will then maintain a set of references to services matching the template and passing the filter. These references are all local to the client and consist of the service proxies and their attributes downloaded to the client. Searching for a service can then be done by local methods : LookupCache.lookup() . These can take an additional filter that can be used to further refine the set of services returned to the client.

The search in the cache is done directly on the proxy services and attributes already found by the client, and does not involve querying lookup services. Essentially, this involves a tradeoff of lookup service activity while the client is idle to produce fast local response when the client is active.

There are versions of ServiceDiscoveryManager.lookup() with a time parameter, which block until a service is found or the method times out. These methods do not use polling, but instead use event notification because they are trying to find services based on remote calls to lookup services. The lookup() methods of LookupCache do not implement such a blocking call because the methods run purely locally, and it is reasonable to poll the cache for a short time if need be.

Here is a version of the file classifier client that creates and examines the cache for a suitable service:

 package client; import common.FileClassifier; import common.MIMEType; import java.rmi.RMISecurityManager; import net.jini.discovery.LookupDiscovery; import net.jini.core.lookup.ServiceTemplate; import net.jini.discovery.LookupDiscoveryManager; import net.jini.lookup.ServiceDiscoveryManager; import net.jini.lookup.LookupCache; import net.jini.core.lookup.ServiceItem; import net.jini.lease.LeaseRenewalManager; /**  * CachedClientLookup.java  */ public class CachedClientLookup {     private static final long WAITFOR = 100000L;     public static void main(String argv[]) {         new CachedClientLookup();         // stay around long enough to receive replies         try {             Thread.currentThread().sleep(WAITFOR);         } catch(java.lang.InterruptedException e) {             // do nothing         }     } public CachedClientLookup() {     ServiceDiscoveryManager clientMgr = null;     LookupCache cache = null;     System.setSecurityManager(new RMISecurityManager());     try {         LookupDiscoveryManager mgr =             new LookupDiscoveryManager(LookupDiscovery.ALL_GROUPS,                                        null /* unicast locators */,                                        null /* DiscoveryListener */);         clientMgr = new ServiceDiscoveryManager(mgr,                                             new LeaseRenewalManager());     } catch(Exception e) {         e.printStackTrace();         System.exit(1);     }     Class [] classes = new Class[] {FileClassifier.class};     ServiceTemplate template = new ServiceTemplate(null, classes,                                                    null);     try {         cache = clientMgr.createLookupCache(template,                                             null, /* no filter */                                             null /* no listener */);     } catch(Exception e) {         e.printStackTrace();         System.exit(1);     }     // loop until we find a service     ServiceItem item = null;     while (item == null) {         System.out.println("no service yet");         try {             Thread.currentThread().sleep(1000);         } catch(java.lang.InterruptedException e) {             // do nothing         }         // see if a service is there now         item = cache.lookup(null);     }     FileClassifier classifier = (FileClassifier) item.service;         if (classifier == null) {             System.out.println("Classifier null");             System.exit(1);         }         // Now we have a suitable service, use it         MIMEType type;         try {             String fileName;             fileName = "file1.txt";             type = classifier.getMIMEType(fileName);             printType(fileName, type);             fileName = "file2.rtf";             type = classifier.getMIMEType(fileName);             printType(fileName, type);             fileName = "file3.abc";             type = classifier.getMIMEType(fileName);             printType(fileName, type);         } catch(java.rmi.RemoteException e) {             System.err.println(e.toString());         }         System.exit(0);     }     private void printType(String fileName, MIMEType type) {         System.out.print("Type of " + fileName + " is ");         if (type == null) {             System.out.println("null");         } else {             System.out.println(type.toString());         }     } } // CachedClientLookup 

Running the CachedClientLookup

While it is okay to poll the local cache, the cache itself must get its contents from lookup services, and in general it is not okay to poll these because that involves possibly heavy network traffic. The cache itself gets its information by registering itself as a listener for service events from the lookup services (as explained in Chapter 14). The lookup services will then call notify() on the cache listener. This call is a remote call from the remote lookup service to the local cache, done (probably) using an RMI stub. In fact, the Sun implementation of ServiceDiscoveryManager uses a nested class, ServiceDiscoveryManager.LookupCacheImpl.LookupListener , which has an RMI stub.

In order for the cache to actually work, it is necessary to set the RMI codebase property, java.rmi.server.codebase , to a suitable location for the class files (such as an HTTP server), and to make sure that the class net/jini/lookup/ServiceDiscoveryManager$LookupCacheImpl$LookupListener_Stub.class is accessible from this codebase. The stub file may be found in the lib/jini-ext.jar library in the Jini 1.1 distribution. It has to be extracted from there and placed in the codebase using a command such as this:

 unzip jini-ext.jar 'net/jini/lookup/ServiceDiscoveryManager$LookupCache- Impl$LookupListener_Stub.class' -d /home/WWW/htdocs/classes 

Note that the specification just says that this type of thing has to be done but does not descend to details about the class name ”that is left to the documentation of the ServiceDiscoveryManager as implemented by Sun. If another implementation is made of the Jini classes, then it would probably use a different remote class.


A Programmer[ap]s Guide to Jini Technology
A Programmer[ap]s Guide to Jini Technology
ISBN: 1893115801
Year: 2000
Pages: 189

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net