previous chapter table of contents next chapter

The Client

The client is the same for all of the possible server implementations discussed throughout this book. The client does not care how the service implementation is done, just as long as it gets a service that it wants, and it specifies this by asking for a FileClassifier interface.

Unicast Client

If there is a known service locator that will know about the service, then there is no need to search for the service locator. This doesn't mean that the location of the service is known, only the location of the locator. For example, there might be a (fictitious) organization "All About Files" at www.all_about_files.com that would know about various file services, keeping track of them as they come online, move, disappear, etc. A client would ask the service locator running on this site for the service, wherever it is. This uses the unicast lookup techniques:

 package client; import common.FileClassifier; import common.MIMEType; import net.jini.core.discovery.LookupLocator; import net.jini.core.lookup.ServiceRegistrar; import net.jini.core.lookup.ServiceItem; import net.jini.core.lookup.ServiceRegistration; import java.rmi.RMISecurityManager; import net.jini.core.lookup.ServiceTemplate; /**  * TestUnicastFileClassifier.java  */ public class TestUnicastFileClassifier { public static void main(String argv[]) {     new TestUnicastFileClassifier(); } public TestUnicastFileClassifier() {     LookupLocator lookup = null;     ServiceRegistrar registrar = null;     FileClassifier classifier = null;     try {         lookup = new LookupLocator("jini://www.all_about_files.com");     } catch(java.net.MalformedURLException e) {         System.err.println("Lookup failed: " + e.toString());         System.exit(1);     }     System.setSecurityManager(new RMISecurityManager());     try {         registrar = lookup.getRegistrar();     } catch (java.io.IOException e) {         System.err.println("Registrar search failed: " + e.toString());         System.exit(1);     } catch (java.lang.ClassNotFoundException e) {         System.err.println("Registrar search failed: " + e.toString());         System.exit(1);     }     Class[] classes = new Class[] {FileClassifier.class};     ServiceTemplate template = new ServiceTemplate(null, classes, null);     try {         classifier = (FileClassifier) registrar.lookup(template);     } catch(java.rmi.RemoteException e) {         e.printStackTrace();         System.exit(1);     }     if (classifier == null) {         System.out.println("Classifier null");         System.exit(2);     }     MIMEType type;     try {             type = classifier.getMIMEType("file1.txt");             System.out.println("Type is " + type.toString());         } catch(java.rmi.RemoteException e) {             System.err.println(e.toString());         }         System.exit(0);     } } // TestUnicastFileClassifier 

The client's JVM is illustrated in Figure 8-1. This shows a UML class diagram, surrounded by the JVM in which the objects exist.

click to expand
Figure 8-1: Objects in client JVM

The client has a main TestFileClassifier class, which has two objects of types LookupDiscovery and MIMEType . It also has objects that implement the interfaces ServiceRegistrar and FileClassifier , but it doesn't know, or need to know, what classes they are. These objects have come across the network as implementation objects of the two interfaces.

Figure 8-2 shows the situation when the service locator's JVM is added in. The lookup service has an object implementing ServiceRegistrar , and this is the object exported to the client.

click to expand
Figure 8-2: Objects in the client and service locator JVMs

This figure shows that the client gets its registrar from the JVM of the service locator. This registrar object is not specified in detail. Sun supplies a service locator known as reggie , which implements the ServiceRegistrar using an implementation that neither clients nor services are expected to know. The classes that implement the ServiceRegistrar object are contained in the reggie-dl.jar file and are downloaded to the clients and services using (typically) an HTTP server.

The figure also shows a question mark for the object in the client implementing FileClassifier . The source of this object is not yet shown; it will get the object from a service, but we haven't yet discussed any of the possible implementations of a FileClassifier service. One implementation will be discussed in the "Chapter 9.

Multicast Client

We have looked at the unicast client, where the location of the service locator is already known. However, it is more likely that a client will need to search for service locators until it finds one holding a service it is looking for. It would need to use a multicast search for this. If it only needs one occurrence of the service, then it can exit after using the service. More complex behavior will be illustrated in later examples.

In this situation, the client does not need to have long- term persistence, but it does need a user thread to remain in existence for long enough to find service locators and find a suitable service. Therefore, in main() a user thread sleeps for a short period (ten seconds).

 package client; import common.FileClassifier; import common.MIMEType; 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; /**  * TestFileClassifier.java  */ public class TestFileClassifier implements DiscoveryListener {     public static void main(String argv[]) {         new TestFileClassifier();         // stay around long enough to receive replies         try {             Thread.currentThread().sleep(100000L);         } catch(java.lang.InterruptedException e) {             // do nothing         }     }     public TestFileClassifier() {         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();         Class [] classes = new Class[] {FileClassifier.class};         FileClassifier classifier = null;         ServiceTemplate template = new ServiceTemplate(null, classes,                                                        null);         for (int n = 0; n < registrars.length; n++) {             System.out.println("Service found");             ServiceRegistrar registrar = registrars[n];             try {                 classifier = (FileClassifier) registrar.lookup(template);             } catch(java.rmi.RemoteException e) {                 e.printStackTrace();                 continue;             }             if (classifier == null) {                 System.out.println("Classifier null");                 continue;             }             // Use the service to classify a few file types             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());                 continue;             }             // success             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());         }     }     public void discarded(DiscoveryEvent evt) {         // empty     } } // TestFileClassifier 

Exception Handling

A Jini program can generate a huge number of exceptions, often related to the network nature of Jini. This is not accidental, but lies at the heart of the Jini approach to network programming. Services can disappear because the link to them has vanished, the server machine has crashed, or the service provider has died. Class files can disappear for similar problems with the HTTP server that delivers them. Timeouts can occur due to unpredictable network delays. Many of these exceptions have their own exception types, such as LookupUnmarshalException , which can occur when unmarshalling objects. Many others are simply wrapped in a RemoteException , which has a detail field for the wrapped exception.

Since many Jini calls can generate exceptions, these must be handled somehow. Many Java programs (or rather, their programmers!) adopt a somewhat cavalier attitude to exceptions: catch them, maybe put out an error message, and continue ”Java makes it easy to handle errors! More seriously, whenever an exception occurs, the question has to be asked: Can the program continue, or has its state been corrupted but not so badly that it cannot recover, or has the program's state been damaged so much that the program must exit.

The multicast TestFileClassifier of the last section can throw exceptions at a number of places:

  • The LookupDiscovery constructor can fail. This is indicative of some serious network error. The created discover object is needed to add a listener, and if this cannot be done, then the program really can't do anything. So it is appropriate to exit with an error value.
  • The ServiceRegistrar.lookup() method can fail. This is indicative of some network error in the connection with a particular service locator. While this may have failed, it is possible that other network connections may succeed. The application can restore a consistent state by skipping the rest of the code in this iteration of the for() loop by using a continue statement.
  • The FileClassifier.getMIMEType() method can fail. This can be caused by a network error, or perhaps the service has simply gone away. Regardless, consistent state can again be restored by skipping the rest of this loop iteration.

Finally, if one part of a program can exit with an abnormal ( non-zero ) error value, then a successful exit should signal its success with an exit value of 0. If this is not done, then the exit value becomes indeterminate and is of no value to other processes that may wish to know whether the program exited successfully or not.


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