Finding a lookup service involves a common series of steps. Subequent interaction with them also involves common steps. A join manager encapulates these into one convenience class for services.
A service needs to locate lookup services and register the service
with them. Locating services can be done using the utility classes of
``Discovery Management''. As each lookup service is discovered, it then needs
to be registered, and the lease maintained. The class JoinManager
performs all of these tasks. There are two constructors
public class JoinManager {
public JoinManager(Object obj,
Entry[] attrSets,
ServiceIDListener callback,
DiscoveryManagement discoverMgr,
LeaseRenewalManager leaseMgr)
throws IOException;
public JoinManager(Object obj,
Entry[] attrSets,
ServiceID serviceID,
DiscoveryManagement discoverMgr,
LeaseRenewalManager leaseMgr)
throws IOException;
}
The first of these is when the service is new and does not have a service id.
A ServiceIDListener
can be added which can note and save the id.
The second form is used when the service already has an id. The other parameters
are for the service and its entry attributes, a DiscoveryManagement
object to set groups and unicast locators (typically this will be done using
a LookupDiscoveryManager
) and a lease renewal manager.
The following example uses this to register a FileClassifierImpl
.
There is no need for a DiscoveryListener
, since the join manager
adds itself as a listener and handles the registration with the lookup service.
package joinmgr;
import rmi.FileClassifierImpl;
import net.jini.lookup.JoinManager;
import net.jini.core.lookup.ServiceID;
import net.jini.discovery.LookupDiscovery;
import net.jini.core.lookup.ServiceRegistrar;
import java.rmi.RemoteException;
import net.jini.lookup.ServiceIDListener;
import net.jini.lease.LeaseRenewalManager;
import net.jini.discovery.LookupDiscoveryManager;
import net.jini.discovery.DiscoveryEvent;
import net.jini.discovery.DiscoveryListener;
/**
* FileClassifierServer.java
*/
public class FileClassifierServer
implements ServiceIDListener {
public static void main(String argv[]) {
new FileClassifierServer();
// stay around forever
Object keepAlive = new Object();
synchronized(keepAlive) {
try {
keepAlive.wait();
} catch(InterruptedException e) {
// do nothing
}
}
}
public FileClassifierServer() {
JoinManager joinMgr = null;
try {
LookupDiscoveryManager mgr =
new LookupDiscoveryManager(LookupDiscovery.ALL_GROUPS,
null /* unicast locators */,
null /* DiscoveryListener */);
joinMgr = new JoinManager(new cokeServer.CokeMachine(), // new FileClassifierImpl(), /* service */
null /* attr sets */,
this /* ServiceIDListener*/,
mgr /* DiscoveryManagement */,
new LeaseRenewalManager());
} catch(Exception e) {
e.printStackTrace();
System.exit(1);
}
}
public void serviceIDNotify(ServiceID serviceID) {
// called as a ServiceIDListener
// Should save the id to permanent storage
System.out.println("got service ID " + serviceID.toString());
}
} // FileClassifierServer
There are a number of other methods in JoinManager
, which allow
one to modify the state of a service registration.
A version of JoinManager
was present in Jini 1.0. At that time
it was in the package com.sun
and
no formal specification was given. Classes in the com.sun
packages may be changed in later versions of Jini, or may even disappear
completely. In moving from Jini 1.0 to Jini 1.1 the JoinManager
classes have now been specified and moved to a new package.
This section describes the old version
for those still using Jini 1.0. When possible, such users should switch
to Jini 1.1
There are a number of possible constructors for JoinManager
.
The simplest is
JoinManager(java.lang.Object obj,
Entry[] attrSets,
ServiceIDListener callback,
LeaseRenewalManager leaseMgr)
This specifies the service to be managed and its entry attributes.
The callback
will have its serviceIDNotify()
method
called when a new locator is discovered. This argument can be
null
if the application has no interest in this.
The leaseMgr
can also be set to null
and
will then be created as needed.
Using this constructor will initiate a search for service locators
belonging to the group ``public'', which is defined by a group value
of the empty string ""
. There is no constant for this,
and the locators from Sun do not appear to belong to this group, so
most applications will need to follow this up immediately with a
call to search for locators belonging to any group:
JoinManager joinMgr = new JoinManager(obj, null, null, null);
joinMgr.setGroups(LookupDiscovery.ALL_GROUPS);
The second constructor
JoinManager(java.lang.Object obj,
Entry[] attrSets,
java.lang.String[] groups,
LookupLocator[] locators,
ServiceIDListener callback,
LeaseRenewalManager leaseMgr)
adds groups
and locators
. This allows
multicast search for locators belonging to certain groups, and
also unicast lookup for known locators. A multicast only search
for any groups would use
JoinManager joinMgr = new JoinManager(obj, null,
LookupDiscovery.ALL_GROUPS,
null, null, null);
where both additional parameters are set to null
.
On the other hand, a unicast lookup for a single known site would be done by
LookupLocator[] locators = new LookupLocator[1];
locators[0] new LookupLocator("http://www.all_about_files.com");
JoinManager joinMgr = new JoinManager(obj, null,
LookupDiscovery.NO_GROUPS,
locators, null, null);
(This code ignored exception handling.)
For example, uploading the complete service of the complete
package can become
package joinmgr;
import complete.FileClassifierImpl;
import com.sun.jini.lookup.JoinManager;
import net.jini.core.lookup.ServiceID;
import com.sun.jini.lookup.ServiceIDListener;
import com.sun.jini.lease.LeaseRenewalManager;
import net.jini.discovery.LookupDiscovery;
/**
* FileClassifierServer1_0.java
*/
public class FileClassifierServer1_0 implements ServiceIDListener {
public static void main(String argv[]) {
new FileClassifierServer1_0();
// stay around long enough to receive replies
try {
Thread.currentThread().sleep(1000000L);
} catch(java.lang.InterruptedException e) {
// do nothing
}
}
public FileClassifierServer1_0() {
JoinManager joinMgr = null;
try {
/* this is one way of doing it
joinMgr = new JoinManager(new FileClassifierImpl(),
null,
this,
new LeaseRenewalManager());
joinMgr.setGroups(null);
*/
/* here is another */
joinMgr = new JoinManager(new FileClassifierImpl(),
null,
LookupDiscovery.ALL_GROUPS,
null,
this,
new LeaseRenewalManager());
} catch(Exception e) {
e.printStackTrace();
System.exit(1);
}
}
public void serviceIDNotify(ServiceID serviceID) {
System.out.println("got service ID " + serviceID.toString());
}
} // FileClassifierServer1_0
The JoinManager
would appear to be unhelpful in supplying
information about the lookup locators it finds. It is available,
but by a slightly circuitous route. A service can register a
ServiceIDListener
to the JoinManager
.
This will be invoked whenever a new locator
is found, by its serviceIDNotify()
method. A
ServiceID
is not particularly useful, so we just ignore
it. However, within this method we do know that a new service locator
has been found.
The complete set of service locators may be found
from the JoinManager
method getJoinSet()
,
whuch returns an array of ServiceRegistrar
's.
We have met this class before: its method getLocator()
will return a LookupLocator
, which has information such
as host in getHost()
. These can be put together as
protected JoinManager joinmgr;
...
joinmgr = new JoinManager(service, null,
this, new LeaseManager());
...
public void serviceIDNotify(ServiceID serviceID) {
ServiceRegistrar registrars = joinmgr.getJoinSet();
for (int n = 0; n < registrar.length; n++) {
LookupLocator locator = registrars[n].getLocator();
String hostName = locator.getHost();
...
}
}
If you want to find out which is the latest locator to be found, it looks
like you will have to cache the previous set, and find which is new in the
array returned. Each call to getJoinSet()
will return a
new array.
A JoinManager
can be used by a server to simplify many of
the aspects of locating lookup services, registering one or more services
and renewing leases for them.
If you found this chapter of value, the full book is available from APress or Amazon . There is a review of the book at Java Zone