previous chapter table of contents next chapter

Searching for Services with the ServiceRegistrar

A client gets a ServiceRegistrar object from the lookup service, and it uses the lookup() method to search for a service stored on that lookup service. Here is the lookup() method:

 public Class ServiceRegistrar {     public java.lang.Object lookup(ServiceTemplate tmpl)                             throws java.rmi.RemoteException;     public ServiceMatches lookup(ServiceTemplate tmpl,                                  int maxMatches)                             throws java.rmi.RemoteException; } 

The first of these methods just finds a service that matches the request. The second finds a set (as many as maxMatches ).

The lookup methods use a class of type ServiceTemplate to specify the service looked for:

 package net.jini.core.lookup; public Class ServiceTemplate {     public ServiceID serviceID;     public java.lang.Class[] serviceTypes;     public Entry[] attributeSetTemplates;     ServiceTemplate(ServiceID serviceID,                     java.lang.Class[] serviceTypes,                     Entry[] attrSetTemplates); } 

Although each service should have been assigned a serviceID by a lookup service, a client might not know the serviceID (it could be the first time the client has looked for this service, for example). In this case, the serviceID is set to null . If the client does know the serviceID , then it can set the value to find the service. The attributeSetTemplates is a set of Entry elements used to match attributes, and it will be discussed in the "Matching Services" section, later in this chapter.

The major parameter of the lookup() methods is a ServiceTemplate , which contains a list of serviceTypes . We know that services export instances of a class, but how does the client ask so that it gets a suitable instance delivered from the lookup locator?

Although the lookup services keep instances of objects for the service, the client will only know about a service from its specification (unless it already has a serviceID for the service), and the specification will almost certainly be a Java interface. Therefore, the client needs to ask using this interface. An interface can have a class object just like ordinary classes, so the list of serviceTypes will typically be a list of class objects for service interfaces. Thus, the client will usually request an interface object.

To be more concrete, suppose a toaster is defined by this interface:

 public interface Toaster extends java.io.Serializable {     public void setDarkness(int dark);     public void startToasting(); } 

A Breville "Extra Lift" toaster would implement this interface in one particular way, as would other toasters:

 public class BrevilleExtraLiftToaster implements Toaster {     public void setDarkness(int dark) {         ...     }     public void startToasting() {         ...     } } 

When the Toaster service starts, it exports an object of class BrevilleExtraLiftToaster to the lookup service. However, the client does not know what type of toaster is out there, so it will make a request like this:

 System.setSecurityManager(new RMISecurityManager());       // specify the interface object     Class[] toasterClasses = new Class[1];     toasterClasses[0] = Toaster.class;     // prepare a search template of serviceID, classes and entries     ServiceTemplate template = new ServiceTemplate(null,                                                    toasterClasses,                                                    null);     // now find a toaster     Toaster toaster = null;     try {         toaster = (Toaster) registrar.lookup(template);     } catch(java.rmi.RemoteException e) {         System.exit(2);     } 

Notice that lookup() can throw an exception. This can occur if, for example, the service requested cannot be de-serialized.

As a result of calling the lookup() method, an object (an instance of a class implementing the Toaster interface) has been transported across to the client, and the object has been coerced to be of this Toaster type. This object has two methods: setDarkness() and startToasting() . No other information is available about the toaster's capabilities because the interface does not specify any more, and in this case the set of attribute values was null . So the client can call either of the two methods:

 toaster.setDarkness(1); toaster.startToasting(); 

Before leaving this discussion, you might wonder what the role of System.setSecurityManager(new RMISecurityManager()) is. A serialized object has been transported across the network and is reconstituted and coerced to an object implementing Toaster . We know that here it will, in fact, be an object of class BrevilleExtraLiftToaster , but the client doesn't need to know that. Or does it? Certainly the client will not have a class definition for this class on its side. But when the toaster object begins to run, then it must run using its BrevilleExtraLiftToaster code! Where does it get it from?

From the server ”most likely by an HTTP request on the server. This means that the Toaster object is loading a class definition across the network, and this requires security access. So a security manager capable of granting this access must be installed before the load request is made.

Note the difference between loading a serialized instance and loading a class definition: the first does not require access rights; only the second does. So if the client had the class definitions of all possible toasters, then it would never need to load a class and would not need a security manager that allows classes to be loaded across the network. This is not likely, but may perhaps be needed in a high-security environment.


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