previous chapter table of contents next chapter

Uploading a Complete Service

The file-classifier service does not rely on any particular properties of its host ”it is not hardware or operating-system dependent, and does not make use of any files on the host side. In this case, it is possible to upload the entire service to the client and let it run there. The proxy is the service, and no processing elements need to be left on the server.

FileClassifier Implementation

The implementation of the FileClassifier is straightforward:

 package complete; import common.MIMEType; import common.FileClassifier; /**  * FileClassifierImpl.java  */ public class FileClassifierImpl implements FileClassifier, java.io.Serializable {     public MIMEType getMIMEType(String fileName) {         if (fileName.endsWith(".gif")) {             return new MIMEType("image", "gif");         } else if (fileName.endsWith(".jpeg")) {             return new MIMEType("image", "jpeg");         } else if (fileName.endsWith(".mpg")) {             return new MIMEType("video", "mpeg");         } else if (fileName.endsWith(".txt")) {             return new MIMEType("text", "plain");         } else if (fileName.endsWith(".html")) {             return new MIMEType("text", "html");         } else             // fill in lots of other types,             // but eventually give up and             return null;     }     public FileClassifierImpl() {         // empty     } } // FileClassifierImpl 

FileClassifierServer Implementation

The service provider for the file-classifier service needs to create an instance of the exportable service object, register this, and keep the lease alive . In the discovered () method, it not only registers the service but also adds it to a LeaseRenewalManager , to keep the lease alive "forever." This manager runs its own threads to keep re-registering the leases, but these are daemon threads. So in the main() method, the user thread goes to sleep for as long as we want the server to stay around.

The following code uses an "unsatisfied wait" condition that will sleep forever until interrupted . Note that if the server does terminate, then the lease will fail to be renewed and the exported service object will be discarded from lookup locators even though the server is not required for delivery of the service.

The serviceID is initially set to null . This may be the first time this service is ever run, or at least the first time it is ever run with this particular implementation. Since service IDs are issued by lookup services, it must remain null until at least the first registration. Then the service ID can be extracted from the registration and reused for all further lookup services. In addition, the service ID can be saved in some permanent form so that if the server crashes and restarts, the service ID can be retrieved from permanent storage. The following server code saves and retrieves this value in a FileClassifier.id file. Note that we get the service ID from the registration, not from the registrar.

 package complete; 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.ServiceItem; import net.jini.core.lookup.ServiceRegistration; import net.jini.core.lease.Lease; import net.jini.core.lookup.ServiceID ; // import com.sun.jini.lease.LeaseRenewalManager; // Jini 1.0 // import com.sun.jini.lease.LeaseListener;       // Jini 1.0 // import com.sun.jini.lease.LeaseRenewalEvent;   // Jini 1.0 import net.jini.lease.LeaseListener;              // Jini 1.1 import net.jini.lease.LeaseRenewalEvent;          // Jini 1.1 import net.jini.lease.LeaseRenewalManager;        // Jini 1.1 import java.io.*; /**  * FileClassifierServer.java   */ public class FileClassifierServer implements DiscoveryListener,                                          LeaseListener { protected LeaseRenewalManager leaseManager = new LeaseRenewalManager(); protected ServiceID serviceID = null; public static void main(String argv[]) {     new FileClassifierServer();     // keep server running forever to     // - allow time for locator discovery and     // - keep re-registering the lease     Object keepAlive = new Object();     synchronized(keepAlive) {         try {             keepAlive.wait();         } catch(java.lang.InterruptedException e) {             // do nothing         }     } } public FileClassifierServer() {     // Try to load the service ID from file.     // It isn't an error if we can't load it, because     // maybe this is the first time this service has run     DataInput din = null;     try {         din = new DataInputStream(new FileInputStream("FileClassifier.id"));         serviceID = new ServiceID(din);     } catch(Exception e) {         // ignore     }     System.setSecurityManager(new RMISecurityManager());     LookupDiscovery discover = null;     try {         discover = new LookupDiscovery(LookupDiscovery.ALL_GROUPS);     } catch(Exception e) {         System.err.println("Discovery failed " + 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++) {         ServiceRegistrar registrar = registrars[n];         ServiceItem item = new ServiceItem(serviceID,                                            new FileClassifierImpl(),                                            null);         ServiceRegistration reg = null;         try {             reg = registrar.register(item, Lease.FOREVER);         } catch(java.rmi.RemoteException e) {             System.err.println("Register exception: " + e.toString());             continue;         }         System.out.println("Service registered with id " + reg.getServiceID());         // set lease renewal in place         leaseManager.renewUntil(reg.getLease(), Lease.FOREVER, this);         // set the serviceID if necessary         if (serviceID == null) {             serviceID = reg.getServiceID();             // try to save the service ID in a file             DataOutputStream dout = null;             try {                 dout = new DataOutputStream(new                                FileOutputStream("FileClassifier.id"));                 serviceID.writeBytes(dout);                 dout.flush();             } catch(Exception e) {                 // ignore             }         }     } } public void discarded(DiscoveryEvent evt) {     }     public void notify(LeaseRenewalEvent evt) {         System.out.println("Lease expired " + evt.toString());     } } // FileClassifierServer 

Figure 8-3 shows the server, by itself, running in its JVM.

click to expand
Figure 8-3: Objects in the server JVM

Figure 8-2 showed that the client receives an object implementi ServiceRegistrar from the service locator (such as reggie ). When we add in the service locator and the client in their JVMs, the picture looks like what is shown in Figure 8-4.

click to expand
Figure 8-4: Objects in all the JVMs

The unknown FileClassifier object in the client is here supplied bythe service object FileClassifierImpl (via the lookup service, where it is stored in passive form).

Client Implementation

The client for this service was discussed earlier in the section "The Client." The client does not need any special information about this implementation of the service and so can remain quite generic.

What Classes Need to Be Where?

In this chapter we have defined the following classes:

  • common.MIMEType (in the section "Common Classes")
  • common.FileClassifier (in the section "Common Classes")
  • complete.FileClassifierImpl (in the section "Uploading a Complete Service")
  • complete.FileClassifierServer (in the section "Uploading a Complete Service")
  • client.TestFileClassifier (in the section "The Client")

These classes are all required to run a file-classifier application that consists of a file-classifier client and a file-classifier service.

Instance objects of these classes could be running on up to four different machines:

  • The server machine for FileClassifier
  • The machine for the lookup service
  • The machine running the TestFileClassifier client
  • An HTTP server will need to run somewhere to deliver the class file definition of FileClassifierImpl to clients

What classes need to be "known" to which machines? The term "known" can refer to different things:

  • The class may be in the CLASSPATH of a JVM.
  • The class may be loadable across the network.
  • The class may be accessible by an HTTP server.

Service Provider

The server running FileClassifierServer needs to know the following classes and interfaces:

  • The common.FileClassifier interface
  • The common.MIMEType class
  • The complete.FileClassifier Server class
  • The complete.FileClassifierImpl class

These classes all need to be in the CLASSPATH of the server.

HTTP Server

The class complete.FileClassifierImpl will need to be accessible to an HTTP server, as discussed in the next section.

Lookup Service

The lookup service does not need to know any of these classes. It just deals with them in the form of a java.rmi.MarshalledObject .


The client needs to know the following:

  • The common.FileClassifier interface
  • The common.MIMEType class
  • The client.TestFileClassifier class

These all need to be in the CLASSPATH of the client. In addition, the client will need to know the class files for complete.FileClassifierImpl. However, these will come across the network as part of the discovery process, and this will be invisible to the client's programmer.

Running the FileClassifier

We now have a FileClassifierServer service and a TestFileClassifier client to run. There should also be at least one lookup locator already running. The CLASSPATH should be set for each to include the classes discussed in the last section, in addition to the standard ones.

A serialized instance of complete.FileClassifierImpl will be passed from the server to the locator and then to the client. Once on the client, the Jini classes will need to be able to restore the FileClassifierImpl object from the instance data and from the class file, and so will need to load the FileClassifierImpl class file from an HTTP server. The location of this class file relative to the server's DocumentRoot will need to be specified by the service invocation. For example, if it is stored /DocumentRoot/classes/complete/FileClassifierImpl.class , then the service will be started by this command:

 java -Djava.rmi.codebase=http://   hostname   /classes \      complete.FileClassifierServer 

In this command, hostname is the name of the host the server is running on. Note that this host name cannot be localhost , because the local host for the server will not be the local host for the client!

The client will be loading a class definition across the network. It will need to allow this in a security policy file with the following statement:

 java -Djava.security.policy=policy.all client.TestFileClassifier 

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