Using Lookup Services 1.What are Lookup Services 2.How Clients use lookup services 3.How Services...

42
Using Lookup Services 1. What are Lookup Services 2. How Clients use lookup services 3. How Services use lookup services 4. Using events
  • date post

    21-Dec-2015
  • Category

    Documents

  • view

    243
  • download

    0

Transcript of Using Lookup Services 1.What are Lookup Services 2.How Clients use lookup services 3.How Services...

Using Lookup Services

1. What are Lookup Services

2. How Clients use lookup services

3. How Services use lookup services

4. Using events

Lookup 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

How 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?

Why does the LUS hold a proxy to itself?

1. It is possible to add attributes to the proxy so clients can find them by attributes

2. It provides a uniform and elegant way to access resources in the Jini network

3. It gives the ability to create a kind of “nested” LUS by holding the proxies of other LUS in every LUS

Now let’s see how to use the lookup service

How clients use lookup service?

Clients can use a lookup service in a number of ways:

1. They can ask for the service by ID from the LUS or by attributes.

2. They can ask the LUS to notify them every time a new service appears or any changes are made in the services.

How 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 .

client

• Client life cycle

• The lookup() functions

• How are templates matched ?

• ServiceInfo (code)

How 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 don’t have orders or instructions how to interact with the LUS ( they don’t have the equivalent to the “join protocol”)

Why is that?

Services are longer-lived entities than clients!

Searching 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.

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;

}

How 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;

}

Matches 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 service’s list of att contains at least one attribute that matches every entry in the template , or if this field is null.

// Find and print services that have ServiceInfo

// attributes.

 import net.jini.discovery.LookupDiscovery;

import net.jini.discovery.DiscoveryEvent;

import net.jini.discovery.DiscoveryListener;

import 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.RemoteException;

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;

class Discoverer implements DiscoveryListener {

public void discovered(DiscoveryEvent ev) {

ServiceRegistrar[] newregs = ev.getRegistrars();

for (int i=0 ; i<newregs.length ; i++) {

addRegistrar(newregs[i]);

}

}

public void discarded(DiscoveryEvent ev) {

ServiceRegistrar[] newregs = ev.getRegistrars();

for (int i=0 ; i<newregs.length ; i++) {

removeRegistrar(newregs[i]);

}

}

}

public ServiceInfoSearcher() throws IOException {

if (System.getSecurityManager() == null) {

System.setSecurityManager(

new RMISecurityManager());

}

// build our template

Entry[] attrTemplates = new Entry[1];

attrTemplates[0] = 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.getServiceID(), reg);

findServices(reg);

}

protected synchronized void removeRegistrar(ServiceRegistrar reg) {

if (!registrars.contains(reg.getServiceID()))

return;

registrars.remove(reg.getServiceID());

}

void findServices(ServiceRegistrar reg) {

try {

ServiceMatches matches = reg.lookup(tmpl, Integer.MAX_VALUE);

for (int i=0 ; i<matches.totalMatches ; i++) {

if (services.contains(matches.items[i].serviceID))

continue;

addService(matches.items[i]);

}

} catch (RemoteException ex) {

System.err.println("Couldn't search for services: " +

ex.getMessage());

}

}

}

protected void addService(ServiceItem item) {

services.put(item.serviceID, item);

System.out.println("New service found: " + item.serviceID);

printServiceInfo(item);

}

protected void printServiceInfo(ServiceItem item) {

for (int i=0 ; i<item.attributeSets.length ; i++) {

if (item.attributeSets[i] instanceof ServiceInfo) {

ServiceInfo info = (ServiceInfo) item.attributeSets[i];

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);

}

}

}

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("Error starting service info searcher: " +

ex.getMessage());

ex.printStackTrace();

}

}

}

service

• The Join protocol

• Basic wrapper uses JoinManager (code)

The join protocol

In order to “find “ a LUS, the service needs to perform the following steps:

A. Create a ServiceItem that holds both the proxy & the attributes of the service

B. Publish the service by calling register() on any ServiceRegistrars found in the discovery process

C. Maintain the lease returned from the LUS

A 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.

Handling 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.

// 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.HelloWorldServiceInterface {

public MyProxy() { }

public String getMessage() {

return "Bonjour, my little turnip...";

}

}

public 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() {

}

}

// 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);

}}}

public 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) {

}

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.");

}

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();

}

protected PersistentData readState()

throws IOException, ClassNotFoundException {

ObjectInputStream in = new ObjectInputStream(New 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);

}

public static void main(String[] args) {

boolean firsttime = false;

String serFileName = null;

File serFile = null;

if (args.length < 1 || args.length > 2) {

usage();

}

if (args.length == 2) {

if (args[0].equals("-f")) {

firsttime = true;

serFileName = args[1];

} else {

usage();

}

} else {

serFileName = args[0];

}

serFile = new File(serFileName);

}

try {

ServiceWrapper wrapper =

new ServiceWrapper(serFile, firsttime);

new Thread(wrapper).start();

} catch (Exception ex) {

ex.printStackTrace();

}

}

}

events

• Soliciting events from LUS

• Receiving events

• Using events (code)

Soliciting events from lookup service

1. Why would a client be interesting in events?

2. How client ask to be notified on event?

3. What kinds of events can happened ?

4. How lookup service notifies the client ?

•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 << 1; // template doesn’t match a given service

int TRANSITION_NOMATCH_MATCH = 1 << 1; // template begins to match the service

int TRANSITION_MATCH_MATCH = 1 << 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 ?

Receiving 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 .

This 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

// 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;

public 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;

}

ServiceEvent serviceEvent = (ServiceEvent) ev;

switch (serviceEvent.getTransition()) {

case ServiceRegistrar.TRANSITION_NOMATCH_MATCH:

addService(serviceEvent.getServiceItem());

break;

case ServiceRegistrar.TRANSITION_MATCH_NOMATCH:

removeService(serviceEvent.getServiceItem());

break;

case ServiceRegistrar.TRANSITION_MATCH_MATCH:

serviceChanged(serviceEvent.getServiceItem());

break;

}

}

}

public ServiceInfoWatcher()

throws IOException, RemoteException {

mgr = new LeaseRenewalManager();

listener = new Listener();

}

protected void removeService(ServiceItem item) {

services.remove(item.serviceID);

System.out.println("Service no longer available: " + item.serviceID);

printServiceInfo(item);

}

protected void serviceChanged(ServiceItem 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);

// 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(ServiceRegistrar 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());

// 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("Error starting watcher: " +

ex.getMessage());

}

}

}