Title: Using Lookup Services
1Using Lookup Services
- What are Lookup Services
- How Clients use lookup services
- How Services use lookup services
- Using events
2Lookup services are Jini services
- Every lookup service supports all the abilities
properties of other Jini services - Every lookup service has a unique ID
- Every lookup service manages leases
- Every lookup service publishes proxies
attributes
3How Is a Lookup Service Different?
- The only difference between a lookup service
proxy and other service proxies is that - Lookup services proxies can be found by
discovery. - Every lookup service holds a ref to its own proxy
proxies of other lookup services . - Why?
4Why does the LUS hold a proxy to itself?
- It is possible to add attributes to the proxy so
clients can find them by attributes - It provides a uniform and elegant way to access
resources in the Jini network - It gives the ability to create a kind of nested
LUS by holding the proxies of other LUS in every
LUS - Now lets see how to use the lookup service
5How clients use lookup service?
- Clients can use a lookup service in a number of
ways - They can ask for the service by ID from the LUS
or by attributes. - They can ask the LUS to notify them every time a
new service appears or any changes are made in
the services. -
6How services use lookup service?
- First of all every service has a unique ID .
This id is given to it the very first time it
runs and stays with it forever!Communicating
between LUS and a service is via the join
protocol which holds all the info that the
service needs for communicating with the
LUSAfter the discovery process finds an LUS, the
service holds a lease to the LUS that should be
renewed as long as the service is active .
7client
- Client life cycle
- The lookup() functions
- How are templates matched ?
- ServiceInfo (code)
8How clients use lookup service
- The client life cycle
- Clients begin their search for services by using
discovery to find LUS, once they found one they
interact directly with the ServiceRegistrar
interface. - Clients dont have orders or instructions how to
interact with the LUS ( they dont have the
equivalent to the join protocol) - Why is that?
- Services are longer-lived entities than clients!
9Searching for services
- The ServiceRegistrar interface supports two
variants of the method called lookup(). - 1.for clients that can completely specify the
service they need by using the template mechanism
- 2.for client that cant specify the service they
need , or for applications that need to find all
the available services. - In both versions of the lookup() the client a
template called ServiceTemplate - In the first lookup version the the LUS will
return null value to the client if no service
matches the template , but if one or more
services matches the template the LUS will select
one and return its proxy object to the client. - In the second version the client also passes an
integer describing the max number of matches it
whishes to have , in this case the LUS returns an
array of ServiceItems called ServiceMatches . - Once the client has this array it can just look
for service it needs by iterate over the array.
10 package net.jini.core.lookup public class
ServiceMatches implements
Serializable public
ServiceMatches(ServiceItem items , int
totalMatches) public ServiceItem
items public int totoalMatches The
ServiceItems returned from the lookup() are
copies of the ServiceItems published by the
services !! package net.jini.core.lookup public
class ServiceItem
implements Serializable public
ServiceItem(ServiceID serrviceID , Object service
, Entry attributeSets) public
ServiceID serviceID public Object
service public Entry
attributeSets
11How are templates matched??
- package net.jini.core.lookup
- public class ServiceTemplate
- implements Serializable
- public ServiceTemplate(ServiceID
serviceID , Class serviceTypes , Entry
attrSetTmpls) - public ServiceID serviceID
- public Class serviceTypes
- public Entry attrSetTempls
-
12Matches if the service ID in the template
matches the ID of the registered service or if
the ID field is null. And the registered
service is an instance of every type in the
serviceTypes or if this field is null. And
the services list of att contains at least one
attribute that matches every entry in the
template , or if this field is null.
13// Find and print services that have ServiceInfo
// attributes. Â import net.jini.discovery.LookupD
iscovery import net.jini.discovery.DiscoveryEvent
import net.jini.discovery.DiscoveryListener imp
ort net.jini.core.lookup.ServiceMatches import
net.jini.core.lookup.ServiceItem import
net.jini.core.lookup.ServiceTemplate import
net.jini.core.lookup.ServiceRegistrar import
net.jini.lookup.entry.ServiceInfo import
net.jini.core.entry.Entry import
java.util.Hashtable import java.rmi.RemoteExcepti
on import java.rmi.RMISecurityManager import
java.io.IOException  public class
ServiceInfoSearcher implements Runnable
protected Hashtable registrars new
Hashtable() protected Hashtable services
new Hashtable() protected ServiceTemplate
tmpl
14 class Discoverer implements DiscoveryListener
public void discovered(DiscoveryEvent ev)
ServiceRegistrar newregs
ev.getRegistrars() for (int i0
iltnewregs.length i)
addRegistrar(newregsi)
public void discarded(DiscoveryEvent
ev) ServiceRegistrar newregs
ev.getRegistrars() for (int i0
iltnewregs.length i)
removeRegistrar(newregsi)
public ServiceInfoSearcher()
throws IOException if (System.getSecurityManage
r() null) System.setSecurityManager(
new RMISecurityManager())
15 // build our template Entry
attrTemplates new Entry1
attrTemplates0 new ServiceInfo(null, null,
null,
null, null, null) tmpl new
ServiceTemplate(null, null, attrTemplates)
// set up for discovery
LookupDiscovery disco new
LookupDiscovery(LookupDiscovery.ALL_GROUPS)
disco.addDiscoveryListener(new Discoverer())
protected synchronized void
addRegistrar(ServiceRegistrar reg) if
(registrars.contains(reg.getServiceID()))
return registrars.put(reg.getServiceI
D(), reg) findServices(reg)
protected synchronized void removeRegistrar(Servic
eRegistrar reg) if (!registrars.contains
(reg.getServiceID())) return
16 registrars.remove(reg.getServiceID())
void findServices(ServiceRegistrar
reg) try ServiceMatches
matches reg.lookup(tmpl, Integer.MAX_VALUE)
for (int i0
iltmatches.totalMatches i)
if (services.contains(matches.itemsi.serviceID))
continue
addService(matches.itemsi)
catch (RemoteException ex)
System.err.println("Couldn't search for services
"
ex.getMessage())
17 protected void addService(ServiceItem item)
services.put(item.serviceID, item)
System.out.println("New service found "
item.serviceID) printServiceInfo(item)
protected void printServiceInfo(Serv
iceItem item) for (int i0
iltitem.attributeSets.length i)
if (item.attributeSetsi instanceof ServiceInfo)
ServiceInfo info
(ServiceInfo) item.attributeSetsi
System.out.println(" Name "
info.name) System.out.println("
Manufacturer " info.manufacturer)
System.out.println(" Vendor "
info.vendor) System.out.println("
Version " info.version)
System.out.println(" Model " info.model)
System.out.println(" Serial
Number " info.serialNumber)
18 public void run() while (true)
try Thread.sleep(Long.MAX_
VALUE) catch (InterruptedException
ex)
public static void main(String args)
try ServiceInfoSearcher searcher
new ServiceInfoSearcher() new
Thread(searcher).start() catch
(Exception ex) System.err.println("E
rror starting service info searcher "
ex.getMessage())
ex.printStackTrace()
19service
- The Join protocol
- Basic wrapper uses JoinManager (code)
20The join protocol
- In order to find a LUS, the service needs to
perform the following steps - Create a ServiceItem that holds both the proxy
the attributes of the service - Publish the service by calling register() on any
ServiceRegistrars found in the discovery process - Maintain the lease returned from the LUS
21A good Jini citizen, joins
- In addition there are some more things that the
service should do in order to be considered as a
nice Jini network member - The Service should use the same unique ID even
across restart and fails. - The Service should hold a list of LUS it expects
to join, this list must survive across restart
and fails - When a service starts it should register itself
with all the LUS in the list using unicast
discovery.
22Handling Leases, Attribute and group updates
- Services renew their leases on registrations, if
at any point the communication with the LUS
fails, the service acts depending on how the LUS
was discovered - If the LUS discovered via multicast discovery the
service should simply forget it by calling
discard() . - If the LUS was discovered by the unicast
discovery, meaning that the LUS was on the
service list, the service should try to reconnect
. - If the service changes the set of attributes, or
is asked to do so, then it should make the change
in all the LUS it registered with. - If the service changes the set of groups it is
member of, or is asked to do so, then it has to
drop itself from all the LUS that are not in the
new group, and start the discovery process on the
LUS that are members in the new group.
23// A basic wrapper that uses JoinManager  package
corejini.chapter8 Â import java.io. import
net.jini.core.lookup.ServiceID import
net.jini.core.discovery.LookupLocator import
net.jini.core.entry.Entry import
com.sun.jini.lookup.JoinManager import
com.sun.jini.lookup.ServiceIDListener import
java.rmi.RMISecurityManager  class MyProxy
implements Serializable, corejini.chapter5.He
lloWorldServiceInterface public
MyProxy() public String getMessage()
return "Bonjour, my little turnip..."
24public class ServiceWrapper implements Runnable
protected JoinManager join null
protected File serFile null protected
Object proxy new MyProxy() // note
static! static class PersistentData
implements Serializable ServiceID
serviceID Entry attrs
String groups LookupLocator
locators public
PersistentData()
25// An inner class to catch ID changes class
IDListener implements ServiceIDListener
public void serviceIDNotify(ServiceID serviceID)
System.out.println("Got service ID
" serviceID) PersistentData state
new PersistentData()
state.serviceID serviceID
state.attrs join.getAttributes()
state.groups join.getGroups()
state.locators join.getLocators()
try writeState(state)
catch (IOException ex)
System.err.println("Couldn't write to file "
ex.getMessage())
ex.printStackTrace()
join.terminate()
System.exit(1)
26public ServiceWrapper(File serFile, boolean
firsttime) throws IOException,
ClassNotFoundException this.serFile
serFile  if (System.getSecurityManager()
null) System.setSecurityManager( new
RMISecurityManager()) if
(firsttime) register() else
reregister() public void
run() while (true) try
Thread.sleep(Long.MAX_VALUE)
catch (InterruptedException ex)
27 protected void register() throws IOException
if (join ! null) throw new
IllegalStateException("Wrapper already
started.") System.out.println("
Starting...") join new
JoinManager(proxy, null, new IDListener() ,
null) protected void reregister()
throws IOException, ClassNotFoundException
if (join ! null) throw new
IllegalStateException("Wrapper already
started.")
28 PersistentData state readState()
System.out.println("Restarting old id is "
state.serviceID) join
new JoinManager(state.serviceID, proxy,
state.attrs, state.groups,
state.locators, null) Â
protected void writeState(PersistentData state)
throws IOException ObjectOutputStream
out new ObjectOutputStream(new
FileOutputStream(serFile))
out.writeObject(state) out.flush()
out.close()
29 protected PersistentData readState()
throws IOException, ClassNotFoundException
ObjectInputStream in new ObjectInputStream(Ne
w FileInputStream(serFile))
PersistentData state (PersistentData)
in.readObject() in.close()
return state static void usage()
System.err.println("Usage
ServiceWrapper " "-f serialization_file"
) System.exit(1)
30public static void main(String args)
boolean firsttime false String
serFileName null File serFile null
if (args.length lt 1 args.length gt 2)
usage() if
(args.length 2) if
(args0.equals("-f"))
firsttime true serFileName
args1 else
usage() else
serFileName args0
serFile new File(serFileName)
31 try ServiceWrapper
wrapper new ServiceWrapper(serFile,
firsttime) new Thread(wrapper).start(
) catch (Exception ex)
ex.printStackTrace()
32events
- Soliciting events from LUS
- Receiving events
- Using events (code)
33Soliciting events from lookup service
- Why would a client be interesting in events?
- How client ask to be notified on event?
- What kinds of events can happened ?
- How lookup service notifies the client ?
34- When a client ask for events to be sent to him he
provides a special flag that determines how the
template is used - The flag can have three possible values
- 1.a service suddenly matches the provided
template. - 2.a service is no longer matches.
- 3.a service is still matching but is
changing. - Client is asking for events by calling notify()
method on the ServiceRegistrar - The flags are
- int TRANSITION_MATCH_NOMATCH 1 ltlt 1 //
template doesnt match a given service - int TRANSITION_NOMATCH_MATCH 1 ltlt 1 //
template begins to match the service - int TRANSITION_MATCH_MATCH 1 ltlt 2 //
a service is changing in some way - The notify() method returns an EventRegistration
to the client .(a simple container class that
contains the source of the event in this case
the ServiceRegistrar that generate the event) ,
and lease for the event registration . - How the client receive the event ?
35Receiving events !
- Requesting for event the client provides an
object that implements the RemoteEventLisener
interface - public interface RemoteEventLisener implements
java.rmi.Remote, java.util.EventLisener - public void notify(RemoteEvent ev)
- throws java.rmi.RemoteExeption ,
UnknownEventExeption -
- Whenever a LUS needs to send an event , it will
construct one and deliver it by calling the
notify(). - The LUS delivers a subclass of RemoteEvent that
provides extra info about the change .
36This subclass is called ServiceEvent. In the
ServiceEvent client can find info about the
service by using the methods getServiceID().
-- that returns the service id. getServiceItem().
-- returns the complete service item that
cause the event.
a new item if the service has changed.
returns null if the
service was deleted. getTransition(). --
returns a flag value indicating what type of
transition occurred
37// like lookup searcher, only uses
events  package corejini.chapter8  import
net.jini.core.lookup.ServiceRegistrar import
net.jini.core.lookup.ServiceEvent import
net.jini.core.lookup.ServiceItem import
net.jini.core.event.RemoteEvent import
net.jini.core.event.EventRegistration import
net.jini.core.event.RemoteEventListener import
net.jini.core.lease.Lease import
com.sun.jini.lease.LeaseRenewalManager import
java.rmi.RemoteException import
java.rmi.server.UnicastRemoteObject import
java.util.Hashtable import java.io.IOException
38public class ServiceInfoWatcher extends
ServiceInfoSearcher protected Listener
listener protected LeaseRenewalManager mgr
protected Hashtable leases new Hashtable()
protected int transitions ServiceRegistrar.
TRANSITION_MATCH_NOMATCH
ServiceRegistrar.TRANSITION_NOMATCH_MATCH
ServiceRegistrar.TRANSITION_MATCH_MATCH
class Listener extends UnicastRemoteObject
implements RemoteEventListener
public Listener() throws RemoteException
public void notify(RemoteEvent ev)
throws RemoteException if (!(ev
instanceof ServiceEvent))
System.err.println("Unexpected event "
ev.getClass().getName()
) return
39 ServiceEvent serviceEvent (ServiceEvent) ev
switch (serviceEvent.getTransition())
case ServiceRegistrar.TRANSITION_NOMATC
H_MATCH addService(serviceEvent.g
etServiceItem()) break
case ServiceRegistrar.TRANSITION_MATCH_NOMATCH
removeService(serviceEvent.getSer
viceItem()) break
case ServiceRegistrar.TRANSITION_MATCH_MATCH
serviceChanged(serviceEvent.getService
Item()) break
public ServiceInfoWatcher()
throws IOException, RemoteException
mgr new LeaseRenewalManager() listener
new Listener()
40protected void removeService(ServiceItem item)
services.remove(item.serviceID)
System.out.println("Service no longer available
" item.serviceID) printServiceInfo(item
) protected void serviceChanged(Service
Item item) services.put(item.serviceID,
item) System.out.println("Service
updated " item.serviceID)
printServiceInfo(item) // overrride
addRegistrar and removeRegistrar to have them
// ask for/terminate event solicitations whenever
we find a // lookup service. protected
void addRegistrar(ServiceRegistrar reg)
try super.addRegistrar(reg)
EventRegistration er
reg.notify(tmpl , transitions,listener,
null,10 60 1000)
41 // do something with lease
leases.put(reg.getServiceID(), er.getLease())
mgr.renewFor(er.getLease(),
Long.MAX_VALUE, null) catch
(RemoteException ex)
System.err.println("Can't solicit event "
ex.getMessage())
protected void removeRegistrar(Servi
ceRegistrar reg) try
super.removeRegistrar(reg)
// terminate leases on this dude.
Lease lease (Lease) leases.get(reg.getServiceID(
)) if (lease null)
return
leases.remove(reg.getServiceID())
42 // May raise unknown lease exception or //
remote exception. Should be ok to ignore //
here... mgr.cancel(lease)
catch (Exception ex)
public static void main(String args)
try ServiceInfoWatcher watcher
new ServiceInfoWatcher() new
Thread(watcher).start() catch
(Exception ex) System.err.println("E
rror starting watcher "
ex.getMessage())