previous chapter table of contents next chapter

Matching Using Local Services

When a user connects their laptop into a brand-new network, they will probably know little about the environment they have joined. If they want to use services in this network, they will probably want to use general terms and have them translated into specific terms for this new environment. For example, the user may want to print a file on a nearby printer. In this situation, there is little likelihood that the new user knows how to work out the distance between themselves and the printers. However, a local service could be running which does know how to calculate physical distances between objects on the network.

Finding a "close enough" printer then becomes a matter of querying service locators both for printers and for a distance service. As each printer is found, the distance service can be asked to calculate the distance between itself and the laptop (or camera, or any other device that wants to print).

The complexity of the task to be done by clients is growing: a client has to find two sets of services, and when it finds one (a printer) invoke the other (the distance service). This calls for lookup processing to be handled in separate threads. In addition, as each locator is found, it may know about printers, it may know about distance services, it may know both, or it may know none! When the client starts up, it will be discovering these services in an arbitrary order, and the code must be structured to deal with this.

These are some of the cases that may arise:

  • A printer may be discovered before any distance service has been found. In this case, the printer must be stored for later distance checking.
  • A printer may be discovered after a distance service has been found. It can be checked immediately.
  • A distance service is found after some printers have been found. This saved set of printers should be checked at this point.

In this problem, we only need to find one distance service, but possibly many printers. The client code given shortly will save printers in a Vector , and save a distance service in a single variable.

In searching for printers, we only want to find those that have location information. However, we do not want to match on any particular values. The client will have to use wildcard patterns in a location object. The location information of a printer will need to be retrieved along with the printer so it can be used. Therefore, instead of just storing printers, we need to store ServiceItem objects, which carry the attribute information as well as the objects.

Of course, for this to work, the client also needs to know where it is! This could be done, for example, by popping up a dialog box asking the user to locate themselves.

A client satisfying these requirements is given in the following program. (The location of the client is hard-coded into the getMyLocation() method for simplicity.)

 package client; import common.Printer; import common.Distance; import java.util.Vector; import java.rmi.RMISecurityManager; import net.jini.discovery.LookupDiscovery; import net.jini.discovery.DiscoveryListener; import net.jini.discovery.DiscoveryEvent; import net.jini.core.lookup.ServiceRegistrar; import net.jini.core.lookup.ServiceTemplate; import net.jini.lookup.entry.Location; import net.jini.core.lookup.ServiceItem; import net.jini.core.lookup.ServiceMatches; import net.jini.core.entry.Entry; /**  * TestPrinterDistance.java  */ public class TestPrinterDistance implements DiscoveryListener {       protected Distance distance = null;     protected Object distanceLock = new Object();     protected Vector printers = new Vector();     public static void main(String argv[]) {         new TestPrinterDistance();         // stay around long enough to receive replies         try {             Thread.currentThread().sleep(10000L);         } catch(java.lang.InterruptedException e) {             // do nothing         }     }     public TestPrinterDistance() {         System.setSecurityManager(new RMISecurityManager());           LookupDiscovery discover = null;         try {             discover = new LookupDiscovery(LookupDiscovery.ALL_GROUPS);         } catch(Exception e) {             System.err.println(e.toString());             System.exit(1);         }         discover.addDiscoveryListener(this);     }     public void discovered(DiscoveryEvent evt) {         ServiceRegistrar[] registrars = evt.getRegistrars();         for (int n = 0; n < registrars.length; n++) {             System.out.println("Service found");             ServiceRegistrar registrar = registrars[n];             new LookupThread(registrar).start();         }     }     public void discarded(DiscoveryEvent evt) {         // empty     }     class LookupThread extends Thread {         ServiceRegistrar registrar;         LookupThread(ServiceRegistrar registrar) {             this.registrar = registrar;         }         public void run() {             synchronized(distanceLock) {                 // only look for one distance service                 if (distance == null) {                     lookupDistance();                 }                 if (distance != null) {                     // found a new distance service                     // process any previously found printers                     synchronized(printers) {                         for (int n = 0; n < printers.size(); n++) {                             ServiceItem item = (ServiceItem) printers.elementAt(n);                             reportDistance(item);                         }                     }                 }             }             ServiceMatches matches = lookupPrinters();             for (int n = 0; n < matches.items.length; n++) {                 if (matches.items[n] != null) {                     synchronized(distanceLock) {                         if (distance != null) {                             reportDistance(matches.items[n]);                         } else {                             synchronized(printers) {                                  printers.addElement(matches.items[n]);                             }                         }                     }                 }             }         }         /*          * We must be protected by the lock on distanceLock here          */         void lookupDistance() {             // If we don't have a distance service, see if this             // locator knows of one             Class[] classes = new Class[] {Distance.class};             ServiceTemplate template = new ServiceTemplate(null, classes,                                                            null);             try {                 distance = (Distance) registrar.lookup(template);             } catch(java.rmi.RemoteException e) {                 e.printStackTrace();              }         }         ServiceMatches lookupPrinters() {             // look for printers with             // wildcard matching on all fields of Location             Entry[] entries = new Entry[] {new Location(null, null, null)};               Class[] classes = new Class[1];             try {                 classes[0] = Class.forName("common.Printer");             } catch(ClassNotFoundException e) {                 System.err.println("Class not found");                  System.exit(1);             }             ServiceTemplate template = new ServiceTemplate(null, classes,                                                            entries);             ServiceMatches matches = null;             try {                 matches = registrar.lookup(template, 10);             } catch(java.rmi.RemoteException e) {                 e.printStackTrace();             }             return matches;         }         /**          * report on the distance of the printer from          * this client          */         void reportDistance(ServiceItem item) {             Location whereAmI = getMyLocation();             Location whereIsPrinter = getPrinterLocation(item);             if (whereIsPrinter != null) {                 int dist = distance.getDistance(whereAmI, whereIsPrinter);                 System.out.println("Found a printer at " + dist +                                    " units of length away");             }         }         Location getMyLocation() {             return new Location("1", "1", "Building 1");         }         Location getPrinterLocation(ServiceItem item) {             Entry[] entries = item.attributeSets;             for (int n = 0; n < entries.length; n++) {                 if (entries[n] instanceof Location) {                     return (Location) entries[n];                 }             }             return null;         }      } } // TestFileClassifier 

A number of services will need to be running. At least one distance service will be needed, implementing the interface Distance

 package common; import net.jini.lookup.entry.Location; /**  * Distance.java  */ public interface Distance extends java.io.Serializable {       int getDistance(Location loc1, Location loc2); } // Distance 

The following is an example implementation of a distance service:

 package complex; import net.jini.lookup.entry.Location; /**  * DistanceImpl.java  */ public class DistanceImpl implements common.Distance {     public DistanceImpl() {     }     /**       * A very naive distance metric      */     public int getDistance(Location loc1, Location loc2) {         int room1, room2;         try {             room1 = Integer.parseInt(loc1.room);             room2 = Integer.parseInt(loc2.room);         } catch(Exception e) {             return 1;         }         int value = room1 - room2;         return (value > 0 ? value : value);     } } // DistanceImpl 

Earlier in this chapter we gave the code for PrinterImpl . A simple program to start up a distance service and two printers is as follows :

 package complex; import printer.PrinterImpl; import printer.PrinterImpl; import complex.DistanceImpl; // import com.sun.jini.lookup.JoinManager; import net.jini.lookup.JoinManager; import net.jini.core.lookup.ServiceID; // import com.sun.jini.lookup.ServiceIDListener; // import com.sun.jini.lease.LeaseRenewalManager; import net.jini.lookup.ServiceIDListener; import net.jini.lease.LeaseRenewalManager; import net.jini.discovery.LookupDiscovery; import net.jini.lookup.entry.Location; import net.jini.core.entry.Entry; import net.jini.discovery.LookupDiscoveryManager; /**   * PrinterServerLocation.java  */ public class PrinterServerLocation implements ServiceIDListener {     public static void main(String argv[]) {         new PrinterServerLocation();         // run forever         Object keepAlive = new Object();         synchronized(keepAlive) {             try {                 keepAlive.wait();             } catch(InterruptedException e) {                 // do nothing             }         }      }      public PrinterServerLocation() {         JoinManager joinMgr = null;         try {             LookupDiscoveryManager mgr =                 new LookupDiscoveryManager(LookupDiscovery.ALL_GROUPS,                                            null /* unicast locators */,                                            null /* DiscoveryListener */);              // distance service             joinMgr = new JoinManager(new DistanceImpl(),                                       null,                                       this,                                       mgr,                                       new LeaseRenewalManager());             // slow printer in room 120             joinMgr = new JoinManager(new PrinterImpl(20),                                       new Entry[] {new Location("1", "120",                                                                  "Building 1")},                                       this,                                       mgr,                                       new LeaseRenewalManager());             // fast printer in room 130             joinMgr = new JoinManager(new PrinterImpl(30),                                       new Entry[] {new Location("1", "130",                                                                 "Building 1")},                                       this,                                       mgr,                                       new LeaseRenewalManager());         } catch(Exception e) {             e.printStackTrace();             System.exit(1);         }      }     public void serviceIDNotify(ServiceID serviceID) {         System.out.println("got service ID " + serviceID.toString());     } } // PrinterServerLocation 

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