This chapter looks at what the client has to do once it has found a service locator and wishes to find a service.
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();
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.