Client Search

This chapter looks at what the client has to do once it has found a service locator and wishes to find a service.

1. ServiceRegistrar

A client gets a ServiceRegistrar object from the lookup service. It uses this to search for a service stored on that lookup service using 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 (upto the maxMatches) requested.

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);
}
The serviceID is null if unknown (when could the client be expected to know it??? If it is repeating a request???). TheattributeSetTemplates is a set of Entry elements to perform matching of attributes, as discussed earlier.

The major parameter to the lookup() method is a list of serviceTypes. Each service exported is an instance of a class; however, an instance of the class cannot be used in a search by the client, because then the client would already have it and would not need to search! The next best thing is a Class object, because then the exported service can be checked to be an instance of that class. But if you have a class object, then why not simply new it on the client side? In general, an exported object would be a subclass of the class requested or an implementation of the interface requested, and in this subclass or implementation would offer more than the client can get just by new'ing the class. So the client will request a superclass object or an interface object.

To be more concrete, a toaster may be defined by an interface


public interface Toaster extends java.io.Serializable {
    public void setDarkness(int dark);
    public void startToasting();
}
A Breville ``Extra Lift'' toaster will implement this in one particular way, as will 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 will make a request such as

    Class[] toasterClasses = new Class[1];
    Toaster toaster = null;
    try {
        toasterClasses[0] = new Class.forName("Toaster");
    } catch(ClassNotFoundException e) {
        System.err.exit(1);
    }
    ServiceTemplate template = new ServiceTemplate(null, classes, 
                                                   null);
    try {
        toaster = (Toaster) registrar.lookup(template);
    } catch(java.rmi.RemoteException e) {
        System.err.exit(2);
    }
Notice that the lookup() can throw an exception. This can occur, if say, the service requested is not serialisable.

At the end of this, an object has been transported across to the client that is an instance of a class implementing the Toaster interface, and has been coerced to be of this type. This object has two methods setDarkness() and startToasting(). No other information is available about the toaster 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


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

2. ServiceMatches

If a client wishes to search for more than one match to a service request from a particular lookup service, then it specifies the maximum number of matches it would like returned in a ServiceMatches object.


package net.jini.core.lookup;

public Class ServiceMatches {
    public ServiceItem[] items;
    public int totalMatches ;
}
The number of elements in items will be the same as totalMatches. However, not all elements of this array need be non-null! Note that in lookup(tmpl) when asking for only one match, an exception can be returned such as when the service is not serialisable. No exception is thrown here, because although one match might be bad, the others may still be okay. So a value of null as the array element value is used to signify this

    ServiceMatches matches = registrar.lookup(template, 10);
    for (int n = 0; n < matches.totalMatches; n++) {
        Toaster toaster = (Toaster) matches.items[n];
	if (toaster != null) {
	    toaster.setDarkness(1);
	    toaster.startToasting();
        }
    }
(which will start upto 10 toasters cooking at once!) (I don't like assuming totalMatches == items.length. Why is this done???)

This file is Copyright ©Jan Newmarch (http://jan.newmarch.name) jan@newmarch.name

The copyright is the OpenContent License (http://www.opencontent.org/opl.shtml), which is the ``document'' version of the GNU OpenSource license.