previous chapter table of contents next chapter

RMI and non-RMI Proxies for FileClassifier

An alternative that is often used for client/server systems instead of message passing is remote procedure calls (RPC). This involves a client that does some local processing and makes some RPC calls to the server. We can also bring this into the Jini world by using a proxy that does some processing on the client side, and that makes use of an RMI proxy/stub when it needs to make calls back to the service. The RPC mechanism would most naturally be done using RMI in Java.

Some file types are more common than others: GIF, DOC, and HTML files, abound, but there are many more types ranging from less common ones, such as FrameMaker MIF files, to downright obscure ones, such as PDP11 overlay files. An implementation of a file classifier might place the common types in a proxy object that makes them quickly available to clients , and the less common ones back on the server, accessible through a (slower) RMI call.


The proxy object will implement FileClassifier so that clients can find it. The implementation will handle some file types locally, but others it will pass on to another object that implements the ExtendedFileClassifier interface. The ExtendedFileClassifier has one method: getExtraMIMEType() . The proxy is told about this other object at constructor time. The FileClassifierProxy class is as follows :

 /**  * FileClassifierProxy.java   */ package extended; import common.FileClassifier; import common.ExtendedFileClassifier; import common.MIMEType; import java.rmi.RemoteException; public class FileClassifierProxy implements FileClassifier {     /**      * The service object that knows lots more MIME types      */     protected ExtendedFileClassifier extension;     public FileClassifierProxy(ExtendedFileClassifier ext) {         this.extension = ext;     }     public MIMEType getMIMEType(String fileName)         throws RemoteException {             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 {             // we don't know it, pass it on to the service             return extension.getExtraMIMEType(fileName);         }     } } // FileClassifierProxy 


The ExtendedFileClassifier interface will be the top-level interface for the service and an RMI proxy for the service. It will be publicly available for all clients to use. An immediate subinterface, RemoteExtendedFileClassifier , will add the Remote interface:

 /**  * ExtendedFileClassifier.java  */ package common; import java.io.Serializable; import java.rmi.RemoteException; public interface ExtendedFileClassifier extends Serializable {     public MIMEType getExtraMIMEType(String fileName)         throws RemoteException; } // ExtendedFileClassifier 


 /**  * RemoteExtendedFileClassifier.java   */ package extended; import java.rmi.Remote; interface RemoteExtendedFileClassifier extends common.ExtendedFileClassifier, Remote { } // RemoteExtendedFileClassifier 


The implementation of the ExtendedFileClassifier interface is done by an ExtendedFileClassifierImpl object. This will also need to extend UnicastRemoteObject so that the RMI runtime can create an RMI proxy for it. Since this object may handle requests from many proxies, an alternative implementation of searching for MIME types using a hash table is given. This is more efficient for repeated searches:

 /**  * ExtendedFileClassifierImpl.java  */ package extended; import java.rmi.server.UnicastRemoteObject; import common.MIMEType; import java.util.HashMap; import java.util.Map; public class ExtendedFileClassifierImpl extends UnicastRemoteObject     implements RemoteExtendedFileClassifier {          /**      * Map of String extensions to MIME types      */     protected Map map = new HashMap();     public ExtendedFileClassifierImpl() throws java.rmi.RemoteException {         /* This object will handle all classification attempts          * that fail in client-side classifiers. It will be around          * a long time, and may be called frequently, so it is worth          * optimizing the implementation by using a hash map          * /         map.put("rtf", new MIMEType("application", "rtf"));         map.put("dvi", new MIMEType("application", "x-dvi"));         map.put("png", new MIMEType("image", "png"));         // etc     }     public MIMEType getExtraMIMEType(String fileName)         throws java.rmi.RemoteException {         MIMEType type;         String fileExtension;         int dotIndex = fileName.lastIndexOf('.');         if (dotIndex == 1  dotIndex + 1 == fileName.length()) {             // can't find suitable suffix             return null;         }         fileExtension= fileName.substring(dotIndex + 1);         type = (MIMEType) map.get(fileExtension);         return type;     } } // ExtendedFileClassifierImpl 


The final piece in this jigsaw puzzle is the server that creates the service (and implicitly the RMI proxy for the service) and also the proxy primed with knowledge of the service:

 package extended; 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 com.sun.jini.lease.LeaseRenewalManager; // import com.sun.jini.lease.LeaseListener; // import com.sun.jini.lease.LeaseRenewalEvent; import net.jini.lease.LeaseRenewalManager; import net.jini.lease.LeaseListener; import net.jini.lease.LeaseRenewalEvent; import java.rmi.RMISecurityManager; /**  * FileClassifierServer.java  */ public class FileClassifierServer implements DiscoveryListener, LeaseListener {     protected FileClassifierProxy proxy;     protected ExtendedFileClassifierImpl impl;     protected LeaseRenewalManager leaseManager = new LeaseRenewalManager();     public static void main(String argv[]) {         new FileClassifierServer();         // RMI keeps this alive     }     public FileClassifierServer() {         try {             impl = new ExtendedFileClassifierImpl();         } catch(Exception e) {             System.err.println("New impl: " + e.toString());             System.exit(1);         }         // set RMI scurity manager         System.setSecurityManager(new RMISecurityManager());         // proxy primed with impl         proxy = new FileClassifierProxy(impl);         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++) {             ServiceRegistrar registrar = registrars[n];             // export the proxy service             ServiceItem item = new ServiceItem(null,                                                proxy,                                                null);             ServiceRegistration reg = null;             try {                 reg = registrar.register(item, Lease.FOREVER);             } catch(java.rmi.RemoteException e) {                 System.err.print("Register exception: ");                 e.printStackTrace();                 continue;             }             try {                 System.out.println("service registered at " +                                    registrar.getLocator().getHost());             } catch(Exception e) {             }             leaseManager.renewUntil(reg.getLease(), Lease.FOREVER, this);         }     }     public void discarded(DiscoveryEvent evt) {     }     public void notify(LeaseRenewalEvent evt) {         System.out.println("Lease expired " + evt.toString());     } } // FileClassifierServer 

What Classes Need to Be Where?

The implementation of the file classifier in this section uses both RMI and non-RMI proxies. As in other implementations , there is a set of classes involved that need to be known to different parts of an application. We have these classes:

  • common.MIMEType
  • common.FileClassifier
  • common.ExtendedFileClassifier
  • extended.FileClassifierProxy
  • extended.RemoteExtendedFileClassifier
  • extended.ExtendedFileServerImpl
  • extended.FileClassifierServer
  • client.TestFileClassifier

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

  • The common.FileClassifier interface
  • The common.MIMEType class
  • The common.ExtendedFileClassifier class
  • The extended.FileClassifierServer class
  • The extended.FileClassifierProxy class
  • The extended.RemoteExtendedFileClassifier class
  • The extended.ExtendedFileServerImpl class

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

In addition, the HTTP server needs to be able to load and store classes. It needs to be able to access the following:

  • The extended.FileClassifierProxy interface
  • The extended.RemoteExtendedFileClassifier class
  • The extended.ExtendedFileServerImpl_Stub class
  • The common.FileClassifier interface
  • The common.MIMEType 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